home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #20 / NN_1992_20.iso / spool / comp / sys / ibm / pc / hardware / 24349 < prev    next >
Encoding:
Text File  |  1992-09-15  |  58.6 KB  |  1,193 lines

  1. Newsgroups: comp.sys.ibm.pc.hardware
  2. Path: sparky!uunet!usc!sol.ctr.columbia.edu!ira.uka.de!uni-heidelberg!rz.uni-karlsruhe.de!usenet
  3. From: S_JUFFA@iravcl.ira.uka.de (|S| Norbert Juffa)
  4. Subject: What you always wanted to know about math coprocessors 4/4
  5. Message-ID: <1992Sep15.163011.11189@rz.uni-karlsruhe.de>
  6. Sender: usenet@rz.uni-karlsruhe.de (USENET News System)
  7. Organization: University of Karlsruhe (FRG) - Informatik Rechnerabt.
  8. Date: Tue, 15 Sep 1992 16:30:11 GMT
  9. X-News-Reader: VMS NEWS 1.23
  10. Lines: 1181
  11.  
  12.          Test results for accuracy of transcendental functions for double
  13.          extended precision as returned by the program TRANCK. 100,000
  14.          trials per function.
  15.  
  16.          %wrong      is the percentage of results that differ from the 'exact'
  17.                      result (infinitely precise result rounded to 64 bits)
  18.          ULP_hi      is the number of results where the returned result was
  19.                      greater than the 'exact' (correctly rounded) result by
  20.                      one ULP (the numeric weight of the last mantissa bit,
  21.                      2**-63 to 2**-64 depending of the size of the number).
  22.          ULPs_hi     is the number of results where the returned result was
  23.                      greater than the 'exact' result by two or more ULPs.
  24.          ULP_lo      is the number of results where the returned result was
  25.                      smaller than the 'exact' (correctly rounded) result by
  26.                      one ULP (the numeric weight of the last mantissa bit,
  27.                      2**-63 to 2**-64 depending of the size of the number).
  28.          ULPs_lo     is the number of results where the returned result was
  29.                      smaller than the 'exact' result by two or more ULPs.
  30.          max ULP err is the maximum deviation of a returned result from the
  31.                      'exact' answer expressed in ULPs.
  32.  
  33.  
  34.          Franke387 V2.4 emulator
  35.                                                                  max
  36.          funct. intervall   %wrong ULP_hi ULPs_hi ULP_lo ULPs_lo ULP err
  37.  
  38.          SIN    0,pi/4      39.042  25301     708  13029       4       2
  39.          COS    0,pi/4      75.714  49827   25887      0       0       3
  40.          TAN    0,pi/4      76.976  14230   10029  24323   28394       9
  41.          ATAN   0,1         55.826  26028    1529  24044    4225       4
  42.          2XM1   0,0.5       96.717      0       0  47910   48807       5
  43.          YL2XP1 0,sqrt(2)-1 93.007    578       9  27416   65004       8
  44.          YL2X   0.1,10      62.252  16817    4712  37082    3641    2953
  45.  
  46.  
  47.          Microsoft's coproc. emulator (part of MS-C and MS-Fortran libraries)
  48.                                                                  max
  49.          funct. intervall   %wrong ULP_hi ULPs_hi ULP_lo ULPs_lo ULP err
  50.  
  51.          SIN    0,pi/4         N/A    N/A     N/A    N/A     N/A     N/A
  52.          COS    0,pi/4         N/A    N/A     N/A    N/A     N/A     N/A
  53.          TAN    0,pi/4      40.828  27764    1520  11445      99       2
  54.          ATAN   0,1         32.307  18893     485  12530     299       2
  55.          2XM1   0,0.5       52.163   8585     189  37745    5644       3
  56.          YL2XP1 0,sqrt(2)-1 88.801   4714     916  14239   68932      11
  57.          YL2X   0.1,10      36.598  13813    3272  13866    5647      11
  58.  
  59.  
  60.          INTEL 8087, 80287
  61.                                                                  max
  62.          funct. intervall   %wrong ULP_hi ULPs_hi ULP_lo ULPs_lo ULP err
  63.  
  64.          SIN    0,pi/4         N/A    N/A     N/A    N/A     N/A     N/A
  65.          COS    0,pi/4         N/A    N/A     N/A    N/A     N/A     N/A
  66.          TAN    0,pi/4      37.001  18756     524  17405     316       2
  67.          ATAN   0,1          9.666   6065       0   3601       0       1
  68.          2XM1   0,0.5       19.920      0       0  19920       0       1
  69.          YL2XP1 0,sqrt(2)-1  7.780    868       0   6912       0       1
  70.          YL2X   0.1,10       1.287    723       0    564       0       1
  71.  
  72.  
  73.          INTEL 387
  74.                                                                  max
  75.          funct. intervall   %wrong ULP_hi ULPs_hi ULP_lo ULPs_lo ULP err
  76.  
  77.          SIN    0,pi/4      28.872   2467       0  26392      13       2
  78.          COS    0,pi/4      27.213  27169      35      9       0       2
  79.          TAN    0,pi/4      10.532    441       0  10091       0       1
  80.          ATAN   0,1          7.088   2386       0   4691       1       2
  81.          2XM1   0,0.5       32.024      0       0  32024       0       1
  82.          YL2XP1 0,sqrt(2)-1 22.611   3461       0  19150       0       1
  83.          YL2X   0.1,10      13.020   6508       0   6512       0       1
  84.  
  85.  
  86.          INTEL 387DX
  87.                                                                  max
  88.          funct. intervall   %wrong ULP_hi ULPs_hi ULP_lo ULPs_lo ULP err
  89.  
  90.          SIN    0,pi/4      28.873   2467       0  26393      13       2
  91.          COS    0,pi/4      27.121  27090      22      9       0       2
  92.          TAN    0,pi/4      10.711    457       0  10254       0       1
  93.          ATAN   0,1          7.088   2386       0   4691       1       2
  94.          2XM1   0,0.5       32.024      0       0  32024       0       1
  95.          YL2XP1 0,sqrt(2)-1 22.611   3461       0  19150       0       1
  96.          YL2X   0.1,10      13.020   6508       0   6512       0       1
  97.  
  98.  
  99.          ULSI 83C87
  100.                                                                  max
  101.          funct. intervall   %wrong ULP_hi ULPs_hi ULP_lo ULPs_lo ULP err
  102.  
  103.          SIN    0,pi/4      35.530   4989       6  30238     297       2
  104.          COS    0,pi/4      43.989  11193     675  31393     728       2
  105.          TAN    0,pi/4      48.539  18880    1015  26349    2295       3
  106.          ATAN   0,1         20.858     62       0  20796       0       1
  107.          2XM1   0,0.5       21.257      4       0  21253       0       1
  108.          YL2XP1 0,sqrt(2)-1 27.893   9446       0  18213     234       2
  109.          YL2X   0.1,10      13.603   9816       0   3787       0       1
  110.  
  111.  
  112.          IIT 3C87
  113.                                                                  max
  114.          funct. intervall   %wrong ULP_hi ULPs_hi ULP_lo ULPs_lo ULP err
  115.  
  116.          SIN    0,pi/4      18.650  11171      0    7479       0       1
  117.          COS    0,pi/4       7.700   3024      0    4676       0       1
  118.          TAN    0,pi/4      20.973   9681      0   11291       1       2
  119.          ATAN   0,1         19.280  13186      0    6094       0       1
  120.          2XM1   0,0.5       25.660  17570      0    8090       0       1
  121.          YL2XP1 0,sqrt(2)-1 45.830  23503   1896   19654     777       3
  122.          YL2X   0.1,10      10.888   5638    357    4845      48       3
  123.  
  124.  
  125.          C&T 38700DX
  126.                                                                  max
  127.          funct. intervall   %wrong ULP_hi ULPs_hi ULP_lo ULPs_lo ULP err
  128.  
  129.          SIN    0,pi/4       1.821   1272      0     549       0       1
  130.          COS    0,pi/4      23.358  12458      0   10901       0       1
  131.          TAN    0,pi/4      17.178  10725      0    6453       0       1
  132.          ATAN   0,1          9.359   7082      0    2277       0       1
  133.          2XM1   0,0.5       15.188   3039      0   12149       0       1
  134.          YL2XP1 0,sqrt(2)-1 19.497  12109      0    7388       0       1
  135.          YL2X   0.1,10      46.868    261      0   46607       0       1
  136.  
  137.  
  138.          CYRIX 83D87
  139.                                                                  max
  140.          funct. intervall   %wrong ULP_hi ULPs_hi ULP_lo ULPs_lo ULP err
  141.  
  142.          SIN    0,pi/4       1.554   1015      0     539       0       1
  143.          COS    0,pi/4       0.925    143      0     782       0       1
  144.          TAN    0,pi/4       4.147    881      0    3266       0       1
  145.          ATAN   0,1          0.656    229      0     427       0       1
  146.          2XM1   0,0.5        2.628   1433      0    1194       0       1
  147.          YL2XP1 0,sqrt(2)-1  3.242    825      0    2417       0       1
  148.          YL2X   0.1,10       0.931    256      0     675       0       1
  149.  
  150.  
  151.          CYRIX 387+
  152.                                                                  max
  153.          funct. intervall   %wrong ULP_hi ULPs_hi ULP_lo ULPs_lo ULP err
  154.  
  155.          SIN    0,pi/4       1.486    864       0    622       0       1
  156.          COS    0,pi/4       2.072     12       0   2060       0       1
  157.          TAN    0,pi/4       0.602     63       0    539       0       1
  158.          ATAN   0,1          0.384     12       0    372       0       1
  159.          2XM1   0,0.5        1.985     27       0   1958       0       1
  160.          YL2XP1 0,sqrt(2)-1  3.662   1705       0   1957       0       1
  161.          YL2X   0.1,10       0.764    367       0    397       0       1
  162.  
  163.  
  164.          INTEL RapidCAD, Intel 486
  165.                                                                  max
  166.          funct. intervall   %wrong ULP_hi ULPs_hi ULP_lo ULPs_lo ULP err
  167.  
  168.          SIN    0,pi/4      16.991   1517       0  15474       0       1
  169.          COS    0,pi/4       9.003   7603       0   1400       0       1
  170.          TAN    0,pi/4      10.532    441       0  10091       0       1
  171.          ATAN   0,1          7.078   2386       0   4691       1       2
  172.          2XM1   0,0.5       32.025      0       0  32025       0       1
  173.          YL2XP1 0,sqrt(2)-1 21.800    533       0  21267       0       1
  174.          YL2X   0.1,10       3.894   1879       0   2015       0       1
  175.  
  176.  
  177.          The test results above indicate that all 80x87 compatibles do not
  178.          exceed Intel's stated error bound of 3 ULPs for the transcendental
  179.          functions. However, some coprocessors are more accurate than others.
  180.          Rating the coprocessors according to the accuracy of their trans-
  181.          cendental functions gives the following list (highest accuracy
  182.          first): Cyrix 387+, Cyrix 83D87, Intel 486, Intel RapidCAD, Intel
  183.          80287(!), C&T 38700DX, Intel 387DX, Intel 80387, IIT 3C87, ULSI 83C87.
  184.          The tests also show that the problems with excessive inaccuracy of
  185.          the transcendental functions in early versions of the IIT coprocessors
  186.          with errors of up to 8 ULPs [8] have been eliminated. According to
  187.          [56], certain problems with the FPATAN instruction on the IIT 3C87
  188.          occuring under the UNIX version of AutoCAD have been corrected in
  189.          June, 1990. The Franke387 has acceptable accuracy for the FSIN, FCOS,
  190.          and FPATAN instructions, taking into consideration that according to
  191.          its documentation, Franke387 uses only 64 bits of precision for the
  192.          intermediate results, while coprocessors typically use 68 bits
  193.          and more. However, the larger error in the FPTAN, F2XM1, FYL2XP1,
  194.          and especially the FYL2X operations show that the emulator doesn't
  195.          use state of the art algorithms, which ensure an error of only a
  196.          very few ULPs even if no extra precise intermediate results are
  197.          available. Microsoft's coprocessor emulator provides transcendental
  198.          functions with rather good accuracy, except for the logarithmic
  199.          operations, which seem to contain some minor flaws.
  200.  
  201.  
  202.          Chips and Technologies has included a program SMDIAG on the diagnostic
  203.          disk V1.0 for the SuperMATH 38700DX to test the compatibility of the
  204.          computational results and flag settings returned by the coprocessor
  205.          with the Intel 387DX. However, the tests for the transcendental
  206.          functions seem to have been tweaked to let the C&T 38700DX pass, while
  207.          coprocessors like the Intel RapidCAD and the Cyrix 83D87 fail. Also,
  208.          SMDIAG shows failure in the FSCALE test for the Intel RapidCAD,
  209.          Cyrix 83D87, Cyrix 387+, and ULSI 83C87, although they return the
  210.          correct result according to Intel's documentation for the Intel
  211.          387DX (Intel's second generation 387), which is indeed returned by
  212.          the 387DX. SMDIAG expects the result returned by the original Intel
  213.          80387.
  214.  
  215.          Results of running the SMDIAG program on 387 compatible coprocessors
  216.          (p = passed, f = failed)
  217.  
  218.                       Intel  Intel  Intel  Cyrix  Cyrix    IIT   ULSI    C&T
  219.          Test      RapidCAD  387DX  80387   387+  83D87   3C87  83C87  38700
  220.  
  221.          1  (fstore)      f      p      p      p      f      f      f      p ##
  222.          2  (fiall)       p      p      p      p      p      p      f      p
  223.          3  (faddsub)     p      p      p      p      p      p      p      p
  224.          4  (faddsub_nr)  p      p      p      p      f      f      f      p
  225.          5  (faddsub_cp)  p      p      p      p      f      f      f      p
  226.          6  (faddsub_dn)  p      p      p      p      f      f      f      p
  227.          7  (faddsub_up)  p      p      p      p      f      f      f      p
  228.          8  (fmul)        p      p      p      p      p      f      f      p
  229.          9  (fdivn)       p      p      p      p      p      p      p      p
  230.          10 (fdiv)        p      p      p      p      p      p      f      p
  231.          11 (fxch)        p      p      p      p      p      p      p      p
  232.          12 (fyl2x)       p      p      p      f      f      f      f      p ++
  233.          13 (fyl2xp1)     f      p      p      f      f      f      f      p ++
  234.          14 (fsqrt)       p      p      p      p      p      p      p      p
  235.          15 (fsincos)     f      p      p      f      f      f      f      p ++
  236.          16 (fptan)       p      p      p      f      p      f      f      p ++
  237.          17 (fpatan)      p      p      p      f      f      f      f      p ++
  238.          18 (f2xm1)       p      p      p      f      f      f      f      p ++
  239.          19 (fscale)      f      f      p      f      f      f      f      p **
  240.          20 (fcom1)       p      p      p      p      p      f      f      p
  241.          21 (fprem)       p      p      p      p      p      p      p      p
  242.          22 (misc1)       p      p      p      p      p      f      f      p
  243.          23 (misc3)       p      p      p      p      p      p      p      p
  244.          24 (misc4)       p      p      p      p      f      f      p      p
  245.  
  246.          failed modules:  4      1      0      7     12     16     17      0
  247.  
  248.  
  249.  
  250.          ## the failure of the Intel RapidCAD is caused by the fact that
  251.             it stores the value of BCD INDEFINITE differently from the
  252.             Intel 387DX. It uses FFFFC000000000000000, while the 387DX uses
  253.             FFFF8000000000000000. However, both encodings are valid according
  254.             to Intel's documentation, which defines the BCD INDEFINITE as
  255.             FFFFUUUUUUUUUUUUUUUU, where U is undefined. So failure of the
  256.             RapidCAD to deliver the same answer as the 387DX is *not* an
  257.             error, just a very slight incompatibility.
  258.          ** the FSCALE errors reported for the Intel 387DX, Intel RapidCAD,
  259.             Cyrix 83D87, Cyrix 387+, and ULSI 83C87 are due to a single
  260.             'wrong' result each returned by one of the FSCALE computations.
  261.             SMDIAG expects the result returned by the first generation
  262.             Intel 80387 (and the C&T 38700DX). However, this result is
  263.             wrong according to Intel's documentation and the behavior was
  264.             corrected in the second generation Intel 387DX. Therefor, the
  265.             Intel RapidCAD, Cyrix 83D87, Cyrix 387+, and ULSI 83C87 return
  266.             the result compatible with the Intel 387DX.
  267.          ++ The failures for the test of transcendental functions are caused
  268.             by the tested coprocessor returning results that differ from the
  269.             ones returned by the Intel 387DX. On the Cyrix 83D87, Cyrix 387+,
  270.             and Intel RapidCAD, this is simply due to the improved accuracy
  271.             these coprocessors provide over the Intel 387DX. The failures of
  272.             the IIT 3C87 and ULSI 83C87 are mainly due to the lesser accuracy
  273.             in the transcendental functions of these coprocesosors, but for
  274.             the IIT 3C87 an additional source of failures is its inability to
  275.             handle extended precision denormals.
  276.  
  277.  
  278.  
  279.  
  280.  
  281.          References
  282.  
  283.          [1]  Schnurer, G.: Zahlenknacker im Vormarsch.
  284.               c't 1992, Heft 4, Seiten 170-186
  285.          [2]  Curnow, H.J.; Wichmann, B.A.: A synthetic benchmark.
  286.               Computer Journal, Vol. 19, No. 1, 1976, pp. 43-49
  287.          [3]  Wichmann, B.A.: Validation code for the Whetstone benchmark.
  288.               NPL Report DITC 107/88, National Physics Laboratory, UK,
  289.               March 1988
  290.          [4]  Curnow, H.J.: Wither Whetstone? The Synthetic Benchmark after
  291.               15 Years.
  292.               In: Aad van der Steen (ed.): Evaluating Supercomputers.
  293.               London: Chapman and Hall 1990
  294.          [5]  Dongarra, J.J.: The Linpack Benchmark: An Explanation.
  295.               In: Aad van der Steen (ed.): Evaluating Supercomputers.
  296.               London: Chapman and Hall 1990
  297.          [6]  Dongarra, J.J.: Performance of Various Computers Using Standard
  298.               Linear Equations Software.
  299.               Report CS-89-85, Computer Science Department, University of
  300.               Tennessee, March 11, 1992
  301.          [7]  Huth, N.: Dichtung und Wahrheit oder Datenblatt und Test.
  302.               Design & Elektronik 1990, Heft 13, Seiten 105-110
  303.          [8]  Ungerer, B.: Sockelfolger.
  304.               c't 1990, Heft 4, Seiten 162-163
  305.          [9]  Coonen, J.T.: Contributions to a Proposed Standard for Binary
  306.               Floating-Point Arithmetic
  307.               Ph.D. thesis, University of California, Berkeley, 1984
  308.          [10] IEEE: IEEE Standard for Binary Floating-Point Arithmetic.
  309.               SIGPLAN Notices, Vol. 22, No. 2, 1985, pp. 9-25
  310.          [11] IEEE Standard for Binary Floating-Point Arithmetic.
  311.               ANSI/IEEE Std 754-1985.
  312.               New York, NY: Institute of Electrical and Electronics
  313.               Engineers 1985
  314.          [12] FasMath 83D87 Compatibility Report. Cyrix Corporation, Nov. 1989
  315.               Order No. B2004
  316.          [13] FasMath 83D87 Accuracy Report. Cyrix Corporation, July 1990
  317.               Order No. B2002
  318.          [14] FasMath 83D87 Benchmark Report. Cyrix Corporation, June 1990
  319.               Order No. B2004
  320.          [15] FasMath 83D87 User's Manual. Cyrix Corporation, June 1990
  321.               Order No. L2001-003
  322.          [16] Brent, R.P.: A FORTRAN multiple-precision arithmetic package.
  323.               ACM Transactions on Mathematical Software, Vol. 4, No. 1,
  324.               March 1978, pp. 57-70
  325.          [17] 387DX User's Manual, Programmer's Reference. Intel Corporation,
  326.               1989
  327.               Order No. 231917-002
  328.          [18] Volder, J.E.: The CORDIC Trigonometric Computing Technique.
  329.               IRE Transactions on Electronic Computers, Vol. EC-8, No. 5,
  330.               September 1959, pp. 330-334
  331.          [19] Walther, J.S.: A unified algorithm for elementary functions.
  332.               AFIPS Conference Proceedings, Vol. 38, SJCC 1971, pp. 379-385
  333.          [20] Esser, R.; Kremer, F.; Schmidt, W.G.: Testrechnungen auf der
  334.               IBM 3090E mit Vektoreinrichtung.
  335.               Arbeitsbericht RRZK-8803, Regionales Rechenzentrum an der
  336.               Universit"at zu Köln, Februar 1988
  337.          [21] McMahon, H.H.: The Livermore Fortran Kernels: A test of the
  338.               numerical performance range.
  339.               Technical Report UCRL-53745, Lawrence Livermore National
  340.               Laboratory, USA, December 1986
  341.          [22] Nave, R.: Implementation of Transcendental Functions on a Numerics
  342.               Processor.
  343.               Microprocessing and Microprogramming, Vol. 11, No. 3-4,
  344.               March-April 1983, pp. 221-225
  345.          [23] Yuen, A.K.: Intel's Floating-Point Processors.
  346.               Electro/88 Conference Record, Boston, MA, USA, 10-12 May 1988,
  347.               pp. 48/5-1 - 48/5-7
  348.          [24] Stiller, A.; Ungerer, B.: Ausgerechnet.
  349.               c't 1990, Heft 1, Seiten 90-92
  350.          [25] Rosch, W.L.: Handfeste Hilfe oder Seifenblase?
  351.               PC Professionell, Juni 1991, Seiten 214-237
  352.          [26] Intel 80286 Hardware Reference Manual. Intel Corporation, 1987
  353.               Order No.210760-002
  354.          [27] AMD 80C287 80-bit CMOS Numeric Processor. Advanced Micro Devices,
  355.               June 1989
  356.               Order No. 11671B/0
  357.          [28] Intel RapidCAD(tm) Engineering CoProcessor Performance Brief.
  358.               Intel Corporation, 1992
  359.          [29] i486(tm) Microprocessor Performance Report. Intel Corporation,
  360.               April 1990
  361.               Order No. 240734-001
  362.          [30] Intel486(tm) DX2 Microprocessor Performance Brief. Intel
  363.               Corporation, March 1992
  364.               Order No. 241254-001
  365.          [31] Abacus 3167 Floating-Point Coprocessor Data Book. Weitek
  366.               Corporation, July 1990
  367.               DOC No. 9030
  368.          [32] WTL 4167 Floating-Point Coprocessor Data Book. Weitek
  369.               Corporation, July 1989
  370.               DOC No. 8943
  371.          [33] Abacus Software Designer's Guide. Weitek Corporation,
  372.               September 1989
  373.               DOC No. 8967
  374.          [34] Stiller, A.: Cache & Carry.
  375.               c't 1992, Heft 6, Seiten 118-130
  376.          [35] Stiller, A.: Cache & Carry, Teil 2.
  377.               c't 1992, Heft 7, Seiten 28-34
  378.          [36] Palmer, J.F.; Morse, S.P.: Die mathematischen Grundlagen der
  379.               Numerik-Prozessoren 8087/80287.
  380.               München: tewi 1985
  381.          [37] 80C187 80-bit Math Coprocessor Data Sheet. Intel Corporation,
  382.               September 1989
  383.               Order No. 270640-003
  384.          [38] IIT-2C87 80-bit Numeric Co-Processor Data Sheet. IIT, May 1990
  385.          [39] Engineering note 4x4 matrix multiply transformation. IIT, 1989
  386.          [40] Tscheuschner, E.: 4 mal 4 auf einen Streich.
  387.               c't 1990, Heft 3, Seiten 266-276
  388.          [41] Goldberg, D.: Computer Arithmetic.
  389.               In: Hennessy, J.L.; Patterson, D.A.: Computer Architecture A
  390.               Quantitative Approach. San Mateo, CA: Morgan Kaufmann 1990
  391.          [42] 8087 Math Coprocessor Data Sheet. Intel Corporation, October 1989,
  392.               Order No. 205835-007
  393.          [43] 8086/8088 User's Manual, Programmer's and Hardware Reference.
  394.               Intel Corporation, 1989
  395.               Order No. 240487-001
  396.          [44] 80286 and 80287 Programmer's Reference Manual. Intel Corporation,
  397.               1987
  398.               Order No. 210498-005
  399.          [45] 80287XL/XLT CHMOS III Math Coprocessor Data Sheet. Intel
  400.               Corporation, May 1990
  401.               Order No. 290376-001
  402.          [46] Cyrix FasMath(tm) 82S87 Coprocessor Data Sheet. Cyrix Coporation,
  403.               1991
  404.               Document 94018-00 Rev. 1.0
  405.          [47] IIT-3C87 80-bit Numeric Co-Processor Data Sheet. IIT, May 1990
  406.          [48] 486(tm)SX(tm) Microprocessor/ 487(tm)SX(tm) Math CoProcessor
  407.               Data Sheet. Intel Corporation, April 1991.
  408.               Order No. 240950-001
  409.          [49] Schnurer, G.: Die gro"se Verlade.
  410.               c't 1991, Heft 7, Seiten 55-57
  411.          [50] Schnurer, G.: Eine 4 f"ur alle.
  412.               c't 1991, Heft 6, Seite 25
  413.          [51] Intel486(tm)DX Microprocessor Data Book. Intel Corporation,
  414.               June 1991
  415.               Order No. 240440-004
  416.          [52] i486(tm) Microprocessor Hardware Reference Manual. Intel
  417.               Corporation, 1990
  418.               Order No. 240552-001
  419.          [53] i486(tm) Microprocessor Programmer's Reference Manual. Intel
  420.               Corporation, 1990
  421.               Order No. 240486-001
  422.          [54] Ungerer, B.: Kalte H"ute.
  423.               c't 1992, Heft 8, Seiten 140-144
  424.          [55] Ungerer, B.: Hei"se Sache.
  425.               c't 1991, Heft 4, Seiten 104-108
  426.          [56] Rosch, W.L.: Handfeste Hilfe oder Seifenblase?
  427.               PC Profesionell, Juni 1991, Seiten 214-237
  428.          [57] Niederkr"uger, W.: Lebendige Vergangenheit.
  429.               c't 1990, Heft 12, Seiten 114-116
  430.          [58] ULSI Math*Co Advanced Math Coprocessor Technical Specification.
  431.               ULSI System, 5/92, Rev. E
  432.          [59] 387(tm)DX Math CoProcessor Data Sheet. Intel Corporation,
  433.               September 1990.
  434.               Order No. 240448-003
  435.          [60] 387(tm) Numerics Coprocessor Extension Data Sheet. Intel
  436.               Corporation, February 1989.
  437.               Order No. 231920-005
  438.          [61] Koren, I.; Zinaty, O.: Evaluating Elementary Functions in a
  439.               Numerical Coprocessor Based on Rational Approximations.
  440.               IEEE Transactions on Computers, Vol. C-39, No. 8, August 1990,
  441.               pp. 1030-1037
  442.          [62] 387(tm) SX Math CoProcessor Data Sheet. Intel Corporation,
  443.               November 1989
  444.               Order No. 240225-005
  445.          [63] Frenkel, G.: Coprocessors Speed Numeric Operations.
  446.               PC-Week, August 27, 1990
  447.          [64] Schnurer, G.; Stiller, A.: Auto-Matt.
  448.               c't 1991, Heft 10, Seiten 94-96
  449.          [65] Grehan, R.: FPU Face-Off.
  450.               Byte, November 1990, pp. 194-200
  451.          [66] Tang, P.T.P.: Testing Computer Arithmetic by Elementary Number
  452.               Theory. Preprint MCS-P84-0889, Mathematics and Computer Science
  453.               Division, Argonne National Laboratory, August 1989
  454.          [67] Ferguson, W.E.: Selecting math coprocessors.
  455.               IEEE Spectrum, July 1991, pp. 38-41
  456.          [68] Schnabel, J.: Viermal 387.
  457.               Computer Pers"onlich 1991, Heft 22, Seiten 153-156
  458.          [69] Hofmann, J.: Starke Rechenknechte.
  459.               mc 1990, Heft 7, Seiten 64-67
  460.          [70] Woerrlein, H.; Hinnenberg, R.: Die Lust an der Power.
  461.               Computer Live 1991, Heft 10, Seiten 138-149
  462.          [71] email from Peter Forsberg (peterf@vnet.ibm.com),
  463.               email from Alan Brown (abrown@Reston.ICL.COM)
  464.          [72] email from Eric Johnson (johnsone%camax01@uunet.UU.NET),
  465.               email from Jerry Whelan (guru@stasi.bradley.edu),
  466.               email from Arto Viitanen (av@cs.uta.fi),
  467.               email from Richard Krehbiel (richk@grebyn.com)
  468.          [73] email from Fred Dunlap (cyrix!volt!fred@texsun.Central.Sun.COM)
  469.          [74] correspondence with Bengt Ask (f89ba@efd.lth.se)
  470.          [75] email from Thomas Hoberg (tmh@prosun.first.gmd.de)
  471.          [76] Microsoft Macro Assembler Programmer's Guide Version 6.0,
  472.               Microsoft Corporation, 1991. Document No. LN06556-0291
  473.  
  474.  
  475.          Manufacturer's addresses
  476.  
  477.          Intel Corporation
  478.          3065 Bowers Avenue
  479.          Santa Clara, CA 95051
  480.          USA
  481.  
  482.          IIT Integrated Information Technology, Inc.
  483.          2540 Mission College Blvd.
  484.          Santa Clara, CA 95054
  485.          USA
  486.  
  487.          ULSI Systems, Inc.
  488.          58 Daggett Drive
  489.          San Jose, CA 95134
  490.          USA
  491.  
  492.          Chips & Technologies, Inc.
  493.          3050 Zanker Road
  494.          San Jose, CA 95134
  495.          USA
  496.  
  497.          Weitek Corporation
  498.          1060 East Arques Avenue
  499.          Sunnyvale, CA 94086
  500.          USA
  501.  
  502.          AMD Advanced Microdevices, Inc.
  503.          901 Thompson Place
  504.          P.O.B. 3453
  505.          Sunnyvale, CA 94088-3453
  506.          USA
  507.  
  508.          Cyrix Corporation
  509.          P.O.B. 850118
  510.          Richardson, TX 75085
  511.          USA
  512.  
  513.  
  514.          Appendix A
  515.  
  516.  
  517.          {$N+,E+}
  518.          PROGRAM PCtrl;
  519.  
  520.          VAR B,c: EXTENDED;
  521.              Precision, L: WORD;
  522.  
  523.          PROCEDURE SetPrecisionControl (Precision: WORD);
  524.          (* This procedure sets the internal precision of the NDP. Available *)
  525.          (* precision values:  0  -  24 bits (SINGLE)                        *)
  526.          (*                    1  -  n.a. (mapped to single)                 *)
  527.          (*                    2  -  53 bits (DOUBLE)                        *)
  528.          (*                    3  -  64 bits (EXTENDED)                      *)
  529.  
  530.          VAR CtrlWord: WORD;
  531.  
  532.          BEGIN {SetPrecisionCtrl}
  533.             IF Precision = 1 THEN
  534.                Precision := 0;
  535.             Precision := Precision SHL 8; { make mask for PC field in ctrl word}
  536.             ASM
  537.                FSTCW    [CtrlWord]        { store NDP control word }
  538.                MOV      AX, [CtrlWord]    { load control word into CPU }
  539.                AND      AX, 0FCFFh        { mask out precision control field }
  540.                OR       AX, [Precision]   { set desired precision in PC field }
  541.                MOV      [CtrlWord], AX    { store new control word }
  542.                FLDCW    [CtrlWord]        { set new precision control in NDP }
  543.             END;
  544.          END; {SetPrecisionCtrl}
  545.  
  546.          BEGIN {main}
  547.             FOR Precision := 1 TO 3 DO BEGIN
  548.                B := 1.2345678901234567890;
  549.                SetPrecisionControl (Precision);
  550.                FOR L := 1 TO 20 DO BEGIN
  551.                   B := Sqrt (B);
  552.                END;
  553.                FOR L := 1 TO 20 DO BEGIN
  554.                   B := B*B;
  555.                END;
  556.                SetPrecisionControl (3);   { full precision for printout }
  557.                WriteLn (Precision, B:28);
  558.             END;
  559.          END.
  560.  
  561.  
  562.          +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  563.  
  564.          {$N+,E+}
  565.          PROGRAM RCtrl;
  566.  
  567.          VAR B,c: EXTENDED;
  568.              RoundingMode, L: WORD;
  569.  
  570.  
  571.          PROCEDURE SetRoundingMode (RCMode: WORD);
  572.          (* This procedure selects one of four available rounding modes *)
  573.          (* 0  -  Round to nearest (default)                            *)
  574.          (* 1  -  Round down (towards negative infinity)                *)
  575.          (* 2  -  Round up (towards positive infinity)                  *)
  576.          (* 3  -  Chop (truncate, round towards zero)                   *)
  577.  
  578.          VAR CtrlWord: WORD;
  579.  
  580.          BEGIN
  581.             RCMode := RCMode SHL 10;      { make mask for RC field in control word}
  582.             ASM
  583.                FSTCW    [CtrlWord]        { store NDP control word }
  584.                MOV      AX, [CtrlWord]    { load control word into CPU }
  585.                AND      AX, 0F3FFh        { mask out rounding control field }
  586.                OR       AX, [RCMode]      { set desired precision in RC field }
  587.                MOV      [CtrlWord], AX    { store new control word }
  588.                FLDCW    [CtrlWord]        { set new rounding control in NDP }
  589.             END;
  590.          END;
  591.  
  592.          BEGIN
  593.             FOR RoundingMode := 0 TO 3 DO BEGIN
  594.                B := 1.2345678901234567890e100;
  595.                SetRoundingMode (RoundingMode);
  596.                FOR L := 1 TO 51 DO BEGIN
  597.                   B := Sqrt (B);
  598.                END;
  599.                   FOR L := 1 TO 51 DO BEGIN
  600.                   B := -B*B;
  601.                END;
  602.                SetRoundingMode (0);        { round to nearest for printout }
  603.                WriteLn (RoundingMode, B:28);
  604.             END;
  605.          END.
  606.  
  607.  
  608.          +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  609.  
  610.          {$N+,E+}
  611.  
  612.          PROGRAM DenormTs;
  613.  
  614.          VAR E: EXTENDED;
  615.              D: DOUBLE;
  616.              S: SINGLE;
  617.  
  618.          BEGIN
  619.             WriteLn ('Testing support and printing of denormals');
  620.             WriteLn;
  621.             Write ('Coprocessor is: ');
  622.             CASE Test8087 OF
  623.                0: WriteLn ('Emulator');
  624.                1: WriteLn ('8087 or compatible');
  625.                2: WriteLn ('80287 or compatible');
  626.                3: WriteLn ('80387 or compatible');
  627.             END;
  628.             WriteLn;
  629.             S := 1.18e-38;
  630.             S := S * 3.90625e-3;
  631.             IF S = 0 THEN
  632.                WriteLn ('SINGLE denormals not supported')
  633.             ELSE BEGIN
  634.                WriteLn ('SINGLE denormals supported');
  635.                WriteLn ('SINGLE denormal prints as:   ', S);
  636.                WriteLn ('Denormal should be printed as 4.60943...E-0041');
  637.             END;
  638.             WriteLn;
  639.             D := 2.24e-308;
  640.             D := D * 3.90625e-3;
  641.             IF D = 0 THEN
  642.                WriteLn ('DOUBLE denormals not supported')
  643.             ELSE BEGIN
  644.                WriteLn ('DOUBLE denormals supported');
  645.                WriteLn ('DOUBLE denormal prints as:   ', D);
  646.                WriteLn ('Denormal should be printed as 8.75...E-0311');
  647.             END;
  648.             WriteLn;
  649.             E := 3.37e-4932;
  650.             E := E * 3.90625e-3;
  651.             IF E = 0 THEN
  652.                WriteLn ('EXTENDED denormals not supported')
  653.             ELSE BEGIN
  654.                WriteLn ('EXTENDED denormals supported');
  655.                WriteLn ('EXTENDED denormal prints as: ', E);
  656.                WriteLn ('Denormal should be printed as 1.3164...E-4934');
  657.             END;
  658.          END.
  659.  
  660.  
  661.          Appendix B
  662.  
  663.  
  664.          ; FILE: APFELM4.ASM
  665.          ; assemble with MASM /e APFELM4 or TASM /e APFELM4
  666.  
  667.  
  668.          CODE        SEGMENT BYTE PUBLIC 'CODE'
  669.                      ASSUME  CS: CODE
  670.  
  671.                      PAGE    ,120
  672.  
  673.                      PUBLIC  APPLE87;
  674.  
  675.          APPLE87     PROC    NEAR
  676.                      PUSH    BP                  ; save caller's base pointer
  677.                      MOV     BP, SP              ; make new frame pointer
  678.                      PUSH    DS                  ; save caller's data segment
  679.                      PUSH    SI                  ; save register
  680.                      PUSH    DI                  ;  variables
  681.                      LDS     BX, [BP+04]         ; pointer to parameter record
  682.                      FINIT                       ; init 80x87          FSP->R0
  683.                      FILD   WORD  PTR [BX+02]    ; maxrad              FSP->R7
  684.                      FLD    QWORD PTR [BX+08]    ; qmax                FSP->R6
  685.                      FSUB   QWORD PTR [BX+16]    ; qmax-qmin           FSP->R6
  686.                      DEC    WORD  PTR [BX+04]    ; ymax-1
  687.                      FIDIV  WORD  PTR [BX+04]    ; (qmax-qmin)/(ymax-1)FSP->R6
  688.                      FSTP   QWORD PTR [BX+16]    ; save delta_q        FSP->R7
  689.                      FLD    QWORD PTR [BX+24]    ; pmax                FSP->R6
  690.                      FSUB   QWORD PTR [BX+32]    ; pmax-pmin           FSP->R6
  691.                      DEC    WORD  PTR [BX+06]    ; xmax-1
  692.                      FIDIV  WORD  PTR [BX+06]    ; delta_p             FSP->R6
  693.                      MOV    AX, [BX]             ; save maxiter,[BX] needed for
  694.                      MOV    [BX+2], AX           ;  80x87 status now
  695.                      XOR    BP, BP               ; y=0
  696.                      FLD    QWORD PTR [BX+08]    ; qmax                FSP->R5
  697.                      CMP    WORD  PTR [BX+40], 0 ; fast mode on 8087 desired ?
  698.                      JE     yloop                ; no, normal mode
  699.                      FSTCW  [BX]                 ; save NDP control word
  700.                      AND    WORD PTR [BX], 0FCFFh; set PCTRL = single precision
  701.                      FLDCW  [BX]                 ; get back NDP control word
  702.          yloop:      XOR    DI, DI               ; x=0
  703.                      FLD    QWORD PTR [BX+32]    ; pmin                FSP->R4
  704.          xloop:      FLDZ                        ; j**2= 0             FSP->R3
  705.                      FLDZ                        ; 2ij = 0             FSP->R2
  706.                      FLDZ                        ; i**2= 0             FSP->R1
  707.                      MOV    CX, [BX+2]           ; maxiter
  708.                      MOV    DL, 41h              ; mask for C0 and C3 cond.bits
  709.          iteration:  FSUB   ST, ST(2)            ; i**2-j**2           FSP->R1
  710.                      FADD   ST, ST(3)            ; i**2-j**2+p = i     FSP->R1
  711.                      FLD    ST(0)                ; duplicate i         FSP->R0
  712.                      FMUL   ST(1), ST            ; i**2                FSP->R0
  713.                      FADD   ST, ST(0)            ; 2i                  FSP->R0
  714.                      FXCH   ST(2)                ; 2*i*j               FSP->R0
  715.                      FADD   ST, ST(5)            ; 2*i*j+q = j         FSP->R0
  716.                      FMUL   ST(2), ST            ; 2*i*j               FSP->R0
  717.                      FMUL   ST, ST(0)            ; j**2                FSP->R0
  718.                      FST    ST(3)                ; save j**2           FSP->R0
  719.                      FADD   ST, ST(1)            ; i**2+j**2           FSP->R0
  720.                      FCOMP  ST(7)                ; i**2+j**2 > maxrad? FSP->R1
  721.                      FSTSW  [BX]                 ; save 80x87 cond.codeFSP->R1
  722.                      TEST   BYTE PTR [BX+1], DL  ; test carry and zero flags
  723.                      LOOPNZ iteration            ; until maxiter if not diverg.
  724.                      MOV    DX, CX               ; number of loops executed
  725.                      NEG    CX                   ; carry set if CX <> 0
  726.                      ADC    DX, 0                ; adjust DX if no. of loops<>0
  727.  
  728.                      ; plot point here (DI = X, BP = y, DX has the color)
  729.  
  730.                      FSTP   ST(0)                ; pop i**2            FSP->R2
  731.                      FSTP   ST(0)                ; pop 2ij             FSP->R3
  732.                      FSTP   ST(0)                ; pop j**2            FSP->R4
  733.                      FADD   ST,ST(2)             ; p=p+delta_p         FSP->R4
  734.                      INC    DI                   ; x:=x+1
  735.                      CMP    DI, [BX+6]           ; x > xmax ?
  736.                      JBE    xloop                ; no, continue on same line
  737.                      FSTP   ST(0)                ; pop p               FSP->R5
  738.                      FSUB   QWORD PTR [BX+16]    ; q=q-delta_q         FSP->R5
  739.                      INC    BP                   ; y:=y+1
  740.                      CMP    BP, [BX+4]           ; y > ymax ?
  741.                      JBE    yloop                ; no, picture not done yet
  742.  
  743.          groesser:   POP    DI                   ; restore
  744.                      POP    SI                   ;  register variables
  745.                      POP    DS                   ; restore caller's data segm.
  746.                      POP    BP                   ; save caller's base pointer
  747.                      RET    4                    ; pop parameters and return
  748.          APPLE87     ENDP
  749.  
  750.          CODE        ENDS
  751.  
  752.                      END
  753.  
  754.          ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  755.  
  756.          UNIT Time;
  757.  
  758.          INTERFACE
  759.  
  760.          FUNCTION Clock: LONGINT;          { same as VMS; time in milliseconds }
  761.  
  762.  
  763.          IMPLEMENTATION
  764.  
  765.          FUNCTION Clock: LONGINT; ASSEMBLER;
  766.          ASM
  767.                     PUSH    DS            { save caller's data segment }
  768.                     XOR     DX, DX        { initialize data segment to }
  769.                     MOV     DS, DX        {  access ticker counter }
  770.                     MOV     BX, 46Ch      { offset of ticker counter in segm.}
  771.                     MOV     DX, 43h       { timer chip control port }
  772.                     MOV     AL, 4         { freeze timer 0 }
  773.                     PUSHF                 { save caller's int flag setting }
  774.                     STI                   { allow update of ticker counter }
  775.                     LES     DI, DS:[BX]   { read BIOS ticker counter }
  776.                     OUT     DX, AL        { latch timer 0 }
  777.                     LDS     SI, DS:[BX]   { read BIOS ticker counter }
  778.                     IN      AL, 40h       { read latched timer 0 lo-byte }
  779.                     MOV     AH, AL        { save lo-byte }
  780.                     IN      AL, 40h       { read latched timer 0 hi-byte }
  781.                     POPF                  { restore caller's int flag }
  782.                     XCHG    AL, AH        { correct order of hi and lo }
  783.                     MOV     CX, ES        { ticker counter 1 in CX:DI:AX }
  784.                     CMP     DI, SI        { ticker counter updated ? }
  785.                     JE      @no_update    { no }
  786.                     OR      AX, AX        { update before timer freeze ? }
  787.                     JNS     @no_update    { no }
  788.                     MOV     DI, SI        { use second }
  789.                     MOV     CX, DS        {  ticker counter }
  790.          @no_update:NOT     AX            { counter counts down }
  791.                     MOV     BX, 36EDh     { load multiplier }
  792.                     MUL     BX            { W1 * M }
  793.                     MOV     SI, DX        { save W1 * M (hi) }
  794.                     MOV     AX, BX        { get M }
  795.                     MUL     DI            { W2 * M }
  796.                     XCHG    BX, AX        { AX = M, BX = W2 * M (lo) }
  797.                     MOV     DI, DX        { DI = W2 * M (hi) }
  798.                     ADD     BX, SI        { accumulate }
  799.                     ADC     DI, 0         {  result }
  800.                     XOR     SI, SI        { load zero }
  801.                     MUL     CX            { W3 * M }
  802.                     ADD     AX, DI        { accumulate }
  803.                     ADC     DX, SI        {  result in DX:AX:BX }
  804.                     MOV     DH, DL        { move result }
  805.                     MOV     DL, AH        {  from DL:AX:BX }
  806.                     MOV     AH, AL        {   to }
  807.                     MOV     AL, BH        {    DX:AX:BH }
  808.                     MOV     DI, DX        { save result }
  809.                     MOV     CX, AX        {  in DI:CX }
  810.                     MOV     AX, 25110     { calculate correction }
  811.                     MUL     DX            {  factor }
  812.                     SUB     CX, DX        { subtract correction }
  813.                     SBB     DI, SI        {  factor }
  814.                     XCHG    AX, CX        { result back }
  815.                     MOV     DX, DI        {  to DX:AX }
  816.                     POP     DS            { restore caller's data segment }
  817.          END;
  818.  
  819.  
  820.          BEGIN
  821.             Port [$43] := $34;           { need rate generator, not square wave}
  822.             Port [$40] := 0;             { generator as prog. by some BIOSes }
  823.             Port [$40] := 0;             { for timer 0 }
  824.          END. { Time }
  825.  
  826.  
  827.          ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  828.  
  829.          {$A+,B-,R-,I-,V-,N+,E+}
  830.          PROGRAM PeakFlop;
  831.  
  832.          USES Time;
  833.  
  834.          TYPE ParamRec = RECORD
  835.                             MaxIter, MaxRad, YMax, XMax: WORD;
  836.                             Qmax, Qmin, Pmax, Pmin: DOUBLE;
  837.                             FastMod: WORD;
  838.                             PlotFkt: POINTER;
  839.                             FLOPS:LONGINT;
  840.                          END;
  841.  
  842.          VAR Param: ParamRec;
  843.              Start: LONGINT;
  844.  
  845.  
  846.          {$L APFELM4.OBJ}
  847.  
  848.          PROCEDURE Apple87 (VAR Param: ParamRec);     EXTERNAL;
  849.  
  850.  
  851.          BEGIN
  852.             WITH Param DO BEGIN
  853.                MaxIter:= 50;
  854.                MaxRad := 30;
  855.                YMax   := 30;
  856.                XMax   := 30;
  857.                Pmin   :=-2.1;
  858.                Pmax   := 1.1;
  859.                Qmin   :=-1.2;
  860.                Qmax   := 1.2;
  861.                FastMod:= Word (FALSE);
  862.                PlotFkt:= NIL;
  863.                Flops  := 0;
  864.             END;
  865.             Start := Clock;
  866.             Apple87 (Param);         { executes 104002 FLOP }
  867.             Start := Clock - Start;  { elapsed time in milliseconds }
  868.             WriteLn ('Peak-MFLOPS: ', 104.002 / Start);
  869.          END.
  870.  
  871.          ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  872.  
  873.          ; FILE: M4X4.ASM
  874.          ;
  875.          ; assemble with TASM /e M4X4 or MASM /e M4X4
  876.  
  877.          CODE      SEGMENT BYTE PUBLIC 'CODE'
  878.  
  879.                    ASSUME  CS:CODE
  880.  
  881.                    PUBLIC  MUL_4x4
  882.                    PUBLIC  IIT_MUL_4x4
  883.  
  884.  
  885.          FSBP0     EQU     DB  0DBh, 0E8h        ; declare special IIT
  886.          FSBP1     EQU     DB  0DBh, 0EBh        ;  instructions
  887.          FSBP2     EQU     DB  0DBh, 0EAh
  888.          F4X4      EQU     DB  0DBh, 0F1h
  889.  
  890.  
  891.          ;---------------------------------------------------------------------
  892.          ;
  893.          ; MUL_4x4 multiplicates a four-by-four matrix by an array of four
  894.          ; dimensional vectors. This operation is needed for 3D transformations
  895.          ; in graphics data processing. There are arrays for each component of
  896.          ; a vector. Thus there is an ; array containing all the x components,
  897.          ; another containing all the y components and so on. Each component is
  898.          ; an 8 byte IEEE floating point number. Two indices into the array of
  899.          ; vectors are given. The first is the index of the vector that will be
  900.          ; processed first, the second is the index of the vector processed
  901.          ; last.
  902.          ;
  903.          ;---------------------------------------------------------------------
  904.  
  905.          MUL_4x4   PROC    NEAR
  906.  
  907.                    AddrX   EQU DWORD PTR [BP+24] ; address of X component array
  908.                    AddrY   EQU DWORD PTR [BP+20] ; address of Y component array
  909.                    AddrZ   EQU DWORD PTR [BP+16] ; address of Z component array
  910.                    AddrW   EQU DWORD PTR [BP+12] ; address of W component array
  911.                    AddrT   EQU DWORD PTR [BP+8]  ; addr. of 4x4 transform. mat.
  912.                    F       EQU WORD  PTR [BP+6]  ; first vector to process
  913.                    K       EQU WORD  PTR [BP+4]  ; last vector to process
  914.                    RetAddr EQU WORD  PTR [BP+2]  ; return address saved by call
  915.                    SavdBP  EQU WORD  PTR [BP+0]  ; saved frame pointer
  916.                    SavdDS  EQU WORD  PTR [BP-2]  ; caller's data segment
  917.  
  918.                    PUSH    BP                    ; save TURBO-Pascal frame pointer
  919.                    MOV     BP, SP                ; new frame pointer
  920.                    PUSH    DS                    ; save TURBO-Pascal data segment
  921.  
  922.                    MOV     CX, K                 ; final index
  923.                    SUB     CX, F                 ; final index - start index
  924.                    JNC     $ok                   ; must not
  925.                    JMP     $nothing              ;  be negative
  926.          $ok:      INC     CX                    ; number of elements
  927.  
  928.                    MOV     SI, F                 ; init offset into arrays
  929.                    SHL     SI, 1                 ; each
  930.                    SHL     SI, 1                 ;  element
  931.                    SHL     SI, 1                 ;   has 8 bytes
  932.  
  933.                    LDS     DI, AddrT             ; addr. of transformation mat.
  934.                    FLD     QWORD PTR [DI]        ; load a[0,0]   = R7
  935.                    FLD     QWORD PTR [DI+8]      ; load a[0,1]   = R6
  936.  
  937.          $mat_mul: LES     BX, AddrX             ; addr. of x component array
  938.                    FLD     QWORD PTR ES:[BX+SI]  ; load x[a]     = R5
  939.                    LES     BX, AddrY             ; addr. of y component array
  940.                    FLD     QWORD PTR ES:[BX+SI]  ; load y[a]     = R4
  941.                    LES     BX, AddrZ             ; addr. of z component array
  942.                    FLD     QWORD PTR ES:[BX+SI]  ; load z[a]     = R3
  943.                    LES     BX, AddrW             ; addr. of w component array
  944.                    FLD     QWORD PTR ES:[BX+SI]  ; load w[a]     = R2
  945.  
  946.                    FLD     ST(5)                 ; load a[0,0]   = R1
  947.                    FMUL    ST, ST(4)             ; a[0,0] * x[a] = R1
  948.                    FLD     ST(5)                 ; load a[0,1]   = R0
  949.                    FMUL    ST, ST(4)             ; a[0,1] * y[a] = R0
  950.                    FADDP   ST(1), ST             ; a[0,0]*x[a]+a[0,1]*y[a]=R1
  951.                    FLD     QWORD PTR [DI+16]     ; load a[0,2]   = R0
  952.                    FMUL    ST, ST(3)             ; a[0,2] * z[a] = R0
  953.                    FADDP   ST(1), ST             ; a[0,0]*x[a]...a[0,2]*z[a]=R1
  954.                    FLD     QWORD PTR [DI+24]     ; load a[0,3]   = R0
  955.                    FMUL    ST, ST(2)             ; a[0,3] * w[a] = R0
  956.                    FADDP   ST(1), ST             ; a[0,0]*x[a]...a[0,3]*w[a]=R1
  957.                    LES     BX, AddrX             ; get address of x vector
  958.                    FSTP    QWORD PTR ES:[BX+SI]  ; write new x[a]
  959.  
  960.                    FLD     QWORD PTR [DI+32]     ; load a[1,0]   = R1
  961.                    FMUL    ST, ST(4)             ; a[1,0] * x[a] = R1
  962.                    FLD     QWORD PTR [DI+40]     ; load a[1,1]   = R0
  963.                    FMUL    ST, ST(4)             ; a[1,1] * y[a] = R0
  964.                    FADDP   ST(1), ST             ; a[1,0]*x[a]+a[1,1]*y[a]=R1
  965.                    FLD     QWORD PTR [DI+48]     ; load a[1,2]   = R0
  966.                    FMUL    ST, ST(3)             ; a[1,2] * z[a] = R0
  967.                    FADDP   ST(1), ST             ; a[1,0]*x[a]...a[1,2]*z[a]=R1
  968.                    FLD     QWORD PTR [DI+56]     ; load a[1,3]   = R0
  969.                    FMUL    ST, ST(2)             ; a[1,3] * w[a] = R0
  970.                    FADDP   ST(1), ST             ; a[1,0]*x[a]...a[1,3]*w[a]=R1
  971.                    LES     BX, AddrY             ; get address of y vector
  972.                    FSTP    QWORD PTR ES:[BX+SI]  ; write new y[a]
  973.  
  974.                    FLD     QWORD PTR [DI+64]     ; load a[2,0]   = R1
  975.                    FMUL    ST, ST(4)             ; a[2,0] * x[a] = R1
  976.                    FLD     QWORD PTR [DI+72]     ; load a[2,1]   = R0
  977.                    FMUL    ST, ST(4)             ; a[2,1] * y[a] = R0
  978.                    FADDP   ST(1), ST             ; a[2,0]*x[a]+a[2,1]*y[a]=R1
  979.                    FLD     QWORD PTR [DI+80]     ; load a[2,2]   = R0
  980.                    FMUL    ST, ST(3)             ; a[2,2] * z[a] = R0
  981.                    FADDP   ST(1), ST             ; a[2,0]*x[a]...a[2,2]*z[a]=R1
  982.                    FLD     QWORD PTR [DI+88]     ; load a[2,3]   = R0
  983.                    FMUL    ST, ST(2)             ; a[2,3] * w[a] = R0
  984.                    FADDP   ST(1), ST             ; a[2,0]*x[a]...a[2,3]*w[a]=R1
  985.                    LES     BX, AddrZ             ; get address of z vector
  986.                    FSTP    QWORD PTR ES:[BX+SI]  ; write new z[a]
  987.  
  988.                    FLD     QWORD PTR [DI+96]     ; load a[3,0]   = R1
  989.                    FMULP   ST(4), ST             ; a[3,0] * x[a] = R5
  990.                    FLD     QWORD PTR [DI+104]    ; load a[3,1]   = R1
  991.                    FMULP   ST(3), ST             ; a[3,1] * y[a] = R4
  992.                    FLD     QWORD PTR [DI+112]    ; load a[3,2]   = R1
  993.                    FMULP   ST(2), ST             ; a[3,2] * z[a] = R3
  994.                    FLD     QWORD PTR [DI+120]    ; load a[3,3]   = R1
  995.                    FMULP   ST(1), ST             ; a[3,3] * w[a] = R2
  996.                    FADDP   ST(1), ST             ; a[3,3]*w[a]+a[3,2]*z[a]=R3
  997.                    FADDP   ST(1), ST             ; a[3,3]*w[a]...a[3,1]*y[a]=R4
  998.                    FADDP   ST(1), ST             ; a[3,3]*w[a]...a[3,0]*x[a]=R5
  999.                    LES     BX, AddrW             ; get address of w vector
  1000.                    FSTP    QWORD PTR ES:[BX+SI]  ; write new w[a]
  1001.  
  1002.                    ADD     SI, 8                 ; new offset into arrays
  1003.                    DEC     CX                    ; decrement element counter
  1004.                    JZ      $done                 ; no elements left, done
  1005.                    JMP     $mat_mul              ; transform next vector
  1006.  
  1007.          $done:    FSTP     ST(0)                ; clear
  1008.                    FSTP     ST(0)                ;  FPU stack
  1009.          $nothing: POP      DS                   ; restore TP data segment
  1010.                    POP      BP                   ; restore TP frame pointer
  1011.                    RET      24                   ; pop parameters and return
  1012.  
  1013.          MUL_4X4   ENDP
  1014.  
  1015.  
  1016.          ;---------------------------------------------------------------------
  1017.          ;
  1018.          ; IIT_MUL_4x4 multiplicates a four-by-four matrix by an array of four
  1019.          ; dimensional vectors. This operation is needed for 3D transformations
  1020.          ; in graphics data processing. There are arrays for each component of
  1021.          ; a vector.  Thus there is an array containing all the x components,
  1022.          ; another containing all the y components and so on. Each component is
  1023.          ; an 8 byte IEEE floating point number. Two indices into the array of
  1024.          ; vectors are given. The first is the index of the vector that will be
  1025.          ; processed first, the second is the index of the vector processed
  1026.          ; last. This subroutine uses the special instructions only available
  1027.          ; on IIT coprocessors to provide fast matrix multiply capabilities.
  1028.          ; So make sure to use it only on IIT coprocessors.
  1029.          ;
  1030.          ;---------------------------------------------------------------------
  1031.  
  1032.          IIT_MUL_4x4   PROC    NEAR
  1033.  
  1034.                    AddrX   EQU DWORD PTR [BP+24] ; address of X component array
  1035.                    AddrY   EQU DWORD PTR [BP+20] ; address of Y component array
  1036.                    AddrZ   EQU DWORD PTR [BP+16] ; address of Z component array
  1037.                    AddrW   EQU DWORD PTR [BP+12] ; address of W component array
  1038.                    AddrT   EQU DWORD PTR [BP+8]  ; addr. of 4x4 transf. matrix
  1039.                    F       EQU WORD  PTR [BP+6]  ; first vector to process
  1040.                    K       EQU WORD  PTR [BP+4]  ; last vector to process
  1041.                    RetAddr EQU WORD  PTR [BP+2]  ; return address saved by call
  1042.                    SavdBP  EQU WORD  PTR [BP+0]  ; saved frame pointer
  1043.                    SavdDS  EQU WORD  PTR [BP-2]  ; caller's data segment
  1044.                    Ctrl87  EQU WORD  PTR [BP-4]  ; caller's 80x87 control word
  1045.  
  1046.                    PUSH    BP                    ; save TURBO-Pascal frame ptr
  1047.                    MOV     BP, SP                ; new frame pointer
  1048.                    PUSH    DS                    ; save TURBO-Pascal data seg.
  1049.                    SUB     SP, 2                 ; make local variabe
  1050.                    FSTCW   [Ctrl87]              ; save 80x87 ctrl word
  1051.                    LES     SI, AddrT             ; ptr to transformation matrix
  1052.                    FINIT                         ; initialize coprocessor
  1053.                    FSBP2                         ; set register bank 2
  1054.                    FLD     QWORD PTR ES:[SI]     ; load a[0,0]
  1055.                    FLD     QWORD PTR ES:[SI+32]  ; load a[1,0]
  1056.                    FLD     QWORD PTR ES:[SI+64]  ; load a[2,0]
  1057.                    FLD     QWORD PTR ES:[SI+96]  ; load a[3,0]
  1058.                    FLD     QWORD PTR ES:[SI+8]   ; load a[0,1]
  1059.                    FLD     QWORD PTR ES:[SI+40]  ; load a[1,1]
  1060.                    FLD     QWORD PTR ES:[SI+72]  ; load a[2,1]
  1061.                    FLD     QWORD PTR ES:[SI+104] ; load a[3,1]
  1062.                    FINIT                         ; initialize coprocessor
  1063.                    FSBP1                         ; set register bank 1
  1064.                    FLD     QWORD PTR ES:[SI+16]  ; load a[0,2]
  1065.                    FLD     QWORD PTR ES:[SI+48]  ; load a[1,2]
  1066.                    FLD     QWORD PTR ES:[SI+80]  ; load a[2,2]
  1067.                    FLD     QWORD PTR ES:[SI+112] ; load a[3,2]
  1068.                    FLD     QWORD PTR ES:[SI+24]  ; load a[0,3]
  1069.                    FLD     QWORD PTR ES:[SI+56]  ; load a[1,3]
  1070.                    FLD     QWORD PTR ES:[SI+88]  ; load a[2,3]
  1071.                    FLD     QWORD PTR ES:[SI+120] ; load a[3,3]
  1072.  
  1073.                                                  ; transformation matrix loaded
  1074.  
  1075.                    MOV     AX, F                 ; index of first vector
  1076.                    MOV     DX, K                 ; index of last vector
  1077.  
  1078.                    MOV     BX, AX                ; index 1st vector to process
  1079.                    MOV     CL, 3                 ; component has 8 (2**3) bytes
  1080.                    SHL     BX, CL                ; compute offset into arrays
  1081.  
  1082.                    FINIT                         ; initialize coprocessor
  1083.                    FSBP0                         ; set register bank 0
  1084.  
  1085.          $mat_loop:LES     SI, AddrW             ; addr. of W component array
  1086.                    FLD     QWORD PTR ES:[SI+BX]  ; W component current vector
  1087.                    LES     SI, AddrZ             ; addr. of Z component array
  1088.                    FLD     QWORD PTR ES:[SI+BX]  ; Z component current vector
  1089.                    LES     SI, AddrY             ; addr. of Y component array
  1090.                    FLD     QWORD PTR ES:[SI+BX]  ; Y component current vector
  1091.                    LES     SI, AddrX             ; addr. of X component array
  1092.                    FLD     QWORD PTR ES:[SI+BX]  ; X component current vector
  1093.                    F4X4                          ; mul 4x4 matrix by 4x1 vector
  1094.                    INC     AX                    ; next vector
  1095.                    MOV     DI, AX                ; next vector
  1096.                    SHL     DI, CL                ; offset of vector into arrays
  1097.  
  1098.                    FSTP    QWORD PTR ES:[SI+BX]  ; store X comp. of curr. vect.
  1099.                    LES     SI, AddrY             ; address of Y component array
  1100.                    FSTP    QWORD PTR ES:[SI+BX]  ; store Y comp. of curr. vect.
  1101.                    LES     SI, AddrZ             ; address of Z component array
  1102.                    FSTP    QWORD PTR ES:[SI+BX]  ; store Z comp. of curr. vect.
  1103.                    LES     SI, AddrW             ; address of W component array
  1104.                    FSTP    QWORD PTR ES:[SI+BX]  ; store W comp. of curr. vect.
  1105.  
  1106.                    MOV     BX, DI                ; ofs nxt vect. in comp. arrays
  1107.                    CMP     AX, DX                ; nxt vector past upper bound?
  1108.                    JLE     $mat_loop             ; no, transform next vector
  1109.                    FLDCW   [Ctrl87]              ; restore orig 80x87 ctrl word
  1110.  
  1111.                    ADD      SP, 2                ; get rid of local variable
  1112.                    POP      DS                   ; restore TP data segment
  1113.                    POP      BP                   ; restore TP frame pointer
  1114.                    RET      24                   ; pop parameters and return
  1115.          IIT_MUL_4x4   ENDP
  1116.  
  1117.          CODE      ENDS
  1118.  
  1119.                    END
  1120.  
  1121.          ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1122.  
  1123.          {$N+,E+}
  1124.  
  1125.          PROGRAM Trnsform;
  1126.  
  1127.          USES Time;
  1128.  
  1129.          CONST VectorLen = 8190;
  1130.  
  1131.          TYPE  Vector    = ARRAY [0..VectorLen] OF DOUBLE;
  1132.                VectorPtr = ^Vector;
  1133.                Mat4      = ARRAY [1..4, 1..4] OF DOUBLE;
  1134.  
  1135.          VAR   X: VectorPtr;
  1136.                Y: VectorPtr;
  1137.                Z: VectorPtr;
  1138.                W: VectorPtr;
  1139.                T: Mat4;
  1140.                K: INTEGER;
  1141.                L: INTEGER;
  1142.                First: INTEGER;
  1143.                Last:  INTEGER;
  1144.                Start: LONGINT;
  1145.                Elapsed:LONGINT;
  1146.  
  1147.          PROCEDURE MUL_4X4     (X, Y, Z, W: VectorPtr;
  1148.                                 VAR T: Mat4; First, Last: INTEGER); EXTERNAL;
  1149.          PROCEDURE IIT_MUL_4X4 (X, Y, Z, W: VectorPtr;
  1150.                                 VAR T: Mat4; First, Last: INTEGER); EXTERNAL;
  1151.  
  1152.          {$L M4X4.OBJ}
  1153.  
  1154.          BEGIN
  1155.             WriteLn ('Test8087 = ', Test8087);
  1156.             New (X);
  1157.             New (Y);
  1158.             New (Z);
  1159.             New (W);
  1160.             FOR L := 1 TO VectorLen DO BEGIN
  1161.                X^ [L] := Random;
  1162.                Y^ [L] := Random;
  1163.                Z^ [L] := Random;
  1164.                W^ [L] := Random;
  1165.             END;
  1166.             X^ [0] := 1;
  1167.             Y^ [0] := 1;
  1168.             Z^ [0] := 1;
  1169.             W^ [0] := 1;
  1170.             FOR K := 1 TO 4 DO BEGIN
  1171.                FOR L := 1 TO 4 DO BEGIN
  1172.                   T [K, L] := (K-1)*4 + L;
  1173.                END;
  1174.             END;
  1175.             First := 0;
  1176.             Last  := 8190;
  1177.             Start := Clock;
  1178.             MUL_4X4 (X, Y, Z, W, T, First, Last);
  1179.             { IIT_MUL_4X4 (X, Y, Z, W, T, First, Last); }
  1180.             Elapsed := Clock - Start;
  1181.             WriteLn ('Number of vectors: ', Last-First+1);
  1182.             WriteLn ('Time: ', Elapsed, ' ms');
  1183.             WriteLn ('Equivalent to ', (28.0*(Last-First+1)/1e6)/
  1184.                      (Elapsed*1e-3):0:4, ' MFLOPS');
  1185.             WriteLn;
  1186.             WriteLn ('Last vector:');
  1187.             WriteLn;
  1188.             WriteLn (X^[Last]);
  1189.             WriteLn (Y^[Last]);
  1190.             WriteLn (Z^[Last]);
  1191.             WriteLn (W^[Last]);
  1192.          END.
  1193.