diff -u --recursive --new-file v2.4.0-test12/linux/CREDITS linux/CREDITS --- v2.4.0-test12/linux/CREDITS Mon Dec 11 17:59:43 2000 +++ linux/CREDITS Sun Dec 31 09:27:57 2000 @@ -502,6 +502,12 @@ S: Las Heras, Mendoza CP 5539 S: Argentina +N: Steven P. Cole +E: scole@lanl.gov +E: elenstev@mesatop.com +D: Various build fixes and kernel documentation. +S: Los Alamos, New Mexico + N: Hamish Coleman E: hamish@zot.apana.org.au D: SEEQ8005 network driver @@ -947,6 +953,14 @@ S: University of California, Riverside S: Riverside, California 92521-0304 S: USA + +N: Hans Grobler +E: grobh@sun.ac.za +D: Various AX.25/ROSE/NETROM + hamradio driver patches +S: Department of Electronic Engineering +S: University of Stellenbosch +S: Stellenbosch, Western Cape +S: South Africa N: Grant Guenther E: grant@torque.net diff -u --recursive --new-file v2.4.0-test12/linux/Documentation/Changes linux/Documentation/Changes --- v2.4.0-test12/linux/Documentation/Changes Mon Dec 11 17:59:43 2000 +++ linux/Documentation/Changes Fri Dec 29 14:35:47 2000 @@ -31,7 +31,7 @@ Eine deutsche Version dieser Datei finden Sie unter . -Last updated: October 25, 2000 +Last updated: December 11, 2000 Chris Ricker (kaboom@gatech.edu or chris.ricker@genetics.utah.edu). @@ -51,8 +51,8 @@ o Gnu C 2.91.66 # gcc --version o Gnu make 3.77 # make --version o binutils 2.9.1.0.25 # ld -v -o util-linux 2.10o # kbdrate -v -o modutils 2.3.18 # insmod -V +o util-linux 2.10o # fdformat --version +o modutils 2.3.21 # insmod -V o e2fsprogs 1.19 # tune2fs --version o pcmcia-cs 3.1.21 # cardmgr -V o PPP 2.4.0 # pppd --version @@ -115,18 +115,18 @@ the kernel source tree for all the gory details. System V shared memory is now implemented via a virtual filesystem. -You do not have to mount it to use it as long as you can live with the -default maxima for shared memory and segments. If you wish to change -these variables, you have to mount it with the options nr_blocks -and / or nr_inodes. POSIX shared memory is also now implemented via a -virtual filesystem. If you want to use it, you'll need to mount the -filesystem. The recommended mount location is /dev/shm, and adding the -following line to /etc/fstab should take care of things: +You do not have to mount it to use it. SYSV shared memory limits are +set via /proc/sys/kernel/shm{max,all,mni}. You should mount the +filesystem under /dev/shm to be able to use POSIX shared +memory. Adding the following line to /etc/fstab should take care of +things: none /dev/shm shm defaults 0 0 Remember to create the directory that you intend to mount shm on if -necessary. +necessary (The entry is automagically created if you use devfs). You +can set limits for the number of blocks and inodes used by the +filesystem with the mount options nr_blocks and nr_inodes. The Logical Volume Manager (LVM) is now in the kernel. If you want to use this, you'll need to install the necessary LVM toolset. @@ -291,7 +291,7 @@ Modutils -------- -o +o Mkinitrd -------- diff -u --recursive --new-file v2.4.0-test12/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.4.0-test12/linux/Documentation/Configure.help Mon Dec 11 17:59:43 2000 +++ linux/Documentation/Configure.help Sun Dec 31 09:37:16 2000 @@ -971,7 +971,7 @@ VIA82CXXX chipset support CONFIG_BLK_DEV_VIA82CXXX - This allows you to to configure your chipset for a better use while + This allows you to configure your chipset for a better use while running (U)DMA: it will allow you to enable efficiently the second channel dma usage, as it may not be set by BIOS. It allows you to pass a kernel command line at boot time in order to set fifo @@ -2352,10 +2352,10 @@ module, say M here and read Documentation/modules.txt. The module will be called agpgart.o. -Intel 440LX/BX/GX support +Intel 440LX/BX/GX/815/840/850 support CONFIG_AGP_INTEL This option gives you AGP support for the GLX component of the - XFree86 4.x on Intel 440LX/BX/GX, 815, and 840 chipsets. + XFree86 4.x on Intel 440LX/BX/GX, 815, 840 and 850 chipsets. For the moment, you should probably say N, unless you want to test the GLX component for XFree86 3.3.6, which can be downloaded from @@ -3210,9 +3210,9 @@ CONFIG_FB_MATROX Say Y here if you have a Matrox Millennium, Matrox Millennium II, Matrox Mystique, Matrox Mystique 220, Matrox Productiva G100, Matrox - Mystique G200, Matrox Millennium G200, Matrox Marvel G200 video or - Matrox G400 card in your box. At this time, support for the G100, - Mystique G200 and Marvel G200 is untested. + Mystique G200, Matrox Millennium G200, Matrox Marvel G200 video, + Matrox G400 or G450 card in your box. At this time, support for the G100 + is untested and support for G450 is highly experimental. This driver is also available as a module ( = code which can be inserted and removed from the running kernel whenever you want). @@ -3241,13 +3241,13 @@ packed pixel and 32 bpp packed pixel. You can also use font widths different from 8. -Matrox G100/G200/G400 support +Matrox G100/G200/G400/G450 support CONFIG_FB_MATROX_G100 - Say Y here if you have a Matrox Productiva G100, Matrox Mystique - G200, Matrox Marvel G200 or Matrox Millennium G200 video card. If - you select "Advanced lowlevel driver options", you should check 8 - bpp packed pixel, 16 bpp packed pixel, 24 bpp packed pixel and 32 - bpp packed pixel. You can also use font widths different from 8. + Say Y here if you have a Matrox G100, G200, G400 or G450 based + video card. If you select "Advanced lowlevel driver options", you + should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp packed + pixel and 32 bpp packed pixel. You can also use font widths + different from 8. If you need support for G400 secondary head, you must first say Y to "I2C support" and "I2C bit-banging support" in the character devices @@ -3270,6 +3270,8 @@ Matrox G400 second head support CONFIG_FB_MATROX_MAVEN + WARNING !!! This support does not work with G450 !!! + Say Y or M here if you want to use a secondary head (meaning two monitors in parallel) on G400 or MGA-TVO add-on on G200. Secondary head is not compatible with accelerated XFree 3.3.x SVGA servers - @@ -3297,6 +3299,30 @@ There is no need for enabling 'Matrox multihead support' if you have only one Matrox card in the box. +Matrox G450 second head support +CONFIG_FB_MATROX_G450 + Say Y or M here if you want to use a secondary head (meaning two + monitors in parallel) on G450. + + If you compile it as module, two modules are created, + matroxfb_crtc2.o and matroxfb_g450.o. Both modules are needed if you + want two independent display devices. + + The driver starts in monitor mode and currently does not support + output in TV modes. You must use the matroxset tool (available + at ftp://platan.vc.cvut.cz/pub/linux/matrox-latest) to swap primary + and secondary head outputs. Secondary head driver always start in + 640x480 resolution and you must use fbset to change it. + + Also do not forget that second head supports only 16 and 32 bpp + packed pixels, so it is a good idea to compile them into the kernel + too. You can use only some font widths, as the driver uses generic + painting procedures (the secondary head does not use acceleration + engine). + + There is no need for enabling 'Matrox multihead support' if you have + only one Matrox card in the box. + Matrox unified driver multihead support CONFIG_FB_MATROX_MULTIHEAD Say Y here if you have more than one (supported) Matrox device in @@ -3548,6 +3574,30 @@ other non-standard types of parallel ports. This causes a performance loss, so most people say N. +Sun Ultra/AX-style hardware +CONFIG_PARPORT_AX + Say Y here if you need support for the parallel port hardware on Sun + Ultra/AX machines. This code is also available as a module (say M), + called parport_ax.o. If in doubt, saying N is the safe plan. + +Amiga built-in parallel port support +CONFIG_PARPORT_AMIGA + Say Y here if you need support for the parallel port hardware on + Amiga machines. This code is also available as a module (say M), + called parport_amiga.o. If in doubt, saying N is the safe plan. + +Atari built-in parallel port support +CONFIG_PARPORT_ATARI + Say Y here if you need support for the parallel port hardware on + Atari machines. This code is also available as a module (say M), + called parport_atari.o. If in doubt, saying N is the safe plan. + +Multiface 3 parallel port card support +CONFIG_PARPORT_MFC3 + Say Y here if you need parallel port support for the MFC3 card. + This code is also available as a module (say M), called + parport_mfc3.o. If in doubt, saying N is the safe plan. + Support IEEE1284 status readback CONFIG_PRINTER_READBACK If you have a device on your parallel port that support this @@ -5198,6 +5248,30 @@ module, say M here and read Documentation/modules.txt and Documentation/scsi.txt . +OnStream SC-x0 SCSI tape support +CONFIG_CHR_DEV_OSST + The OnStream SC-x0 SCSI tape drives can not be driven by the + standard st driver, but instead need this special osst driver and + use the /dev/osstX char device nodes (major 206). + Via usb-storage and ide-scsi, you may be able to drive the USB-x0 + and DI-x0 drives as well. Note that there is also a second generation + of OnStream tape drives (ADR-x0) that supports the standard SCSI-2 + commands for tapes (QIC-157) and can be driven by the standard + driver st. + For more information, you may have a look at the SCSI-HOWTO + ftp://metalab.unc.edu/pub/Linux/docs/HOWTO and + drivers/scsi/README.osst in the kernel source. + More info on the OnStream driver may be found on + http://linux1.onstream.nl/test/ + Please also have a look at the standard st docu, as most of it + applies to osst as well. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called osst.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt and + Documentation/scsi.txt . + SCSI CDROM support CONFIG_BLK_DEV_SR If you want to use a SCSI CDROM under Linux, say Y and read the @@ -13140,40 +13214,35 @@ will issue the hlt instruction if nothing is to be done, thereby sending the processor to sleep and saving power. -ACPI support +ACPI Support CONFIG_ACPI - The Advanced Configuration and Power Interface is a standard - designed to allow the operating system more control over power - management issues, such as suspending a computer in a low power - consumption state after a certain time of inaction. It aims to be - an improved version of APM (see below). ACPI has to be - supported by the motherboard. You can read more about the standard - at http://www.teleport.com/~acpi/ . - - If your computer supports ACPI and you want to use it, say Y here. - You will then need supporting software; for location and more - information, please read Documentation/pm.txt and the Battery - Powered Linux mini-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . - - If you say Y here and also to "Advanced Power Management" (APM) - below, then ACPI has precedence in the sense that, if your hardware - supports ACPI, it will be used and APM won't. - -ACPI interpreter (EXPERIMENTAL) -CONFIG_ACPI_INTERPRETER - If you say Y here, an ACPI interpreter will be included in your - kernel, eventually making the full range of ACPI features - available on systems that support ACPI. Note, this option will - enlarge your kernel by about 120K. - - The interpreter is currently experimental so only say Y if - you know what you are doing. - -Enter S1 for sleep (EXPERIMENTAL) -CONFIG_ACPI_S1_SLEEP - If you say Y here, ACPI compliant devices can enter level 1 of ACPI - saving power levels. Basically, this will let them enter sleep mode. + ACPI/OSPM support for Linux is currently under development. As such, + this support is preliminary and EXPERIMENTAL. Configuring ACPI support + enables kernel interfaces that allow higher level software (OSPM) to + manipulate ACPI defined hardware and software interfaces, including + the evaluation of ACPI control methods. If unsure, choose N here. + Note, this option will enlarge your kernel by about 120K. + + This support requires an ACPI compliant platform (hardware/firmware). + If both ACPI and Advanced Power Management (APM) support are + configured, ACPI is used. + + This code DOES NOT currently provide a complete OSPM implementation -- + it has not yet reached APM's level of functionality. When fully + implemented, Linux ACPI/OSPM will provide a more robust functional + replacement for legacy configuration and power management interfaces, + including the Plug-and-Play BIOS specification (PNP BIOS), the Multi- + Processor Specification (MPS), and the Advanced Power Management + specification (APM). + + Linux support for ACPI/OSPM is based on Intel Corporation's ACPI + Component Architecture (ACPI CA). The latest ACPI CA source code, + documentation, debug builds, and implementation status information + can be downloaded from: + http://developer.intel.com/technology/iapc/acpi/downloads.htm + + The ACPI mailing list may also be of interest: + http://phobos.fs.tum.de/acpi/index.html Advanced Power Management BIOS support CONFIG_APM diff -u --recursive --new-file v2.4.0-test12/linux/Documentation/DocBook/Makefile linux/Documentation/DocBook/Makefile --- v2.4.0-test12/linux/Documentation/DocBook/Makefile Sun Oct 8 10:50:04 2000 +++ linux/Documentation/DocBook/Makefile Sat Dec 30 18:16:13 2000 @@ -1,6 +1,6 @@ BOOKS := wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml \ kernel-api.sgml parportbook.sgml kernel-hacking.sgml \ - kernel-locking.sgml via-audio.sgml mousedrivers.sgml + kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml PS := $(patsubst %.sgml, %.ps, $(BOOKS)) PDF := $(patsubst %.sgml, %.pdf, $(BOOKS)) @@ -51,6 +51,10 @@ $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/sound/via82cxxx_audio.c \ via-audio.sgml +sis900.sgml: sis900.tmpl $(TOPDIR)/drivers/net/sis900.c + $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/net/sis900.c \ + sis900.sgml + mcabook.sgml: mcabook.tmpl $(TOPDIR)/arch/i386/kernel/mca.c $(TOPDIR)/scripts/docgen $(TOPDIR)/arch/i386/kernel/mca.c \ mcabook.sgml @@ -72,6 +76,7 @@ $(TOPDIR)/drivers/sound/sound_firmware.c \ $(TOPDIR)/drivers/net/wan/syncppp.c \ $(TOPDIR)/drivers/net/wan/z85230.c \ + $(TOPDIR)/drivers/usb/usb.c \ $(TOPDIR)/fs/locks.c \ $(TOPDIR)/fs/devfs/base.c \ $(TOPDIR)/kernel/pm.c \ diff -u --recursive --new-file v2.4.0-test12/linux/Documentation/DocBook/kernel-api.tmpl linux/Documentation/DocBook/kernel-api.tmpl --- v2.4.0-test12/linux/Documentation/DocBook/kernel-api.tmpl Sun Oct 8 10:50:04 2000 +++ linux/Documentation/DocBook/kernel-api.tmpl Sat Dec 30 18:16:13 2000 @@ -150,6 +150,10 @@ !Idrivers/sound/sound_firmware.c + + USB Devices +!Edrivers/usb/usb.c + 16x50 UART Driver diff -u --recursive --new-file v2.4.0-test12/linux/Documentation/DocBook/kernel-locking.tmpl linux/Documentation/DocBook/kernel-locking.tmpl --- v2.4.0-test12/linux/Documentation/DocBook/kernel-locking.tmpl Wed Jul 5 12:57:06 2000 +++ linux/Documentation/DocBook/kernel-locking.tmpl Fri Dec 29 14:07:19 2000 @@ -155,7 +155,7 @@ - add 1 (5) + add 1 (6) write very_important_count (6) diff -u --recursive --new-file v2.4.0-test12/linux/Documentation/DocBook/sis900.tmpl linux/Documentation/DocBook/sis900.tmpl --- v2.4.0-test12/linux/Documentation/DocBook/sis900.tmpl Wed Dec 31 16:00:00 1969 +++ linux/Documentation/DocBook/sis900.tmpl Fri Dec 29 14:07:19 2000 @@ -0,0 +1,585 @@ + + + + + + +SiS 900/7016 Fast Ethernet Device Driver + + + +Ollie +Lho + + + +Lei Chun +Chang + + + +Document Revision: 0.3 for SiS900 driver v1.06 & v1.07 +November 16, 2000 + + + 1999 + Silicon Integrated System Corp. + + + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + + + +This document gives some information on installation and usage of SiS 900/7016 +device driver under Linux. + + + + + + + + + Introduction + + +This document describes the revision 1.06 and 1.07 of SiS 900/7016 Fast Ethernet +device driver under Linux. The driver is developed by Silicon Integrated +System Corp. and distributed freely under the GNU General Public License (GPL). +The driver can be compiled as a loadable module and used under Linux kernel +version 2.2.x. (rev. 1.06) +With minimal changes, the driver can also be used under 2.3.x and 2.4.x kernel +(rev. 1.07), please see +. If you are intended to +use the driver for earlier kernels, you are on your own. + + + +The driver is tested with usual TCP/IP applications including +FTP, Telnet, Netscape etc. and is used constantly by the developers. + + + +Please send all comments/fixes/questions to +Lei-Chun Chang. + + + + + Changes + + +Changes made in Revision 1.07 + + + + +Separation of sis900.c and sis900.h in order to move most +constant definition to sis900.h (many of those constants were +corrected) + + + + + +Clean up PCI detection, the pci-scan from Donald Becker were not used, +just simple pci_find_*. + + + + + +MII detection is modified to support multiple mii transceiver. + + + + + +Bugs in read_eeprom, mdio_* were removed. + + + + + +Lot of sis900 irrelevant comments were removed/changed and +more comments were added to reflect the real situation. + + + + + +Clean up of physical/virtual address space mess in buffer +descriptors. + + + + + +Better transmit/receive error handling. + + + + + +The driver now uses zero-copy single buffer management +scheme to improve performance. + + + + + +Names of variables were changed to be more consistent. + + + + + +Clean up of auo-negotiation and timer code. + + + + + +Automatic detection and change of PHY on the fly. + + + + + +Bug in mac probing fixed. + + + + + +Fix 630E equalier problem by modifying the equalizer workaround rule. + + + + + +Support for ICS1893 10/100 Interated PHYceiver. + + + + + +Support for media select by ifconfig. + + + + + +Added kernel-doc extratable documentation. + + + + + + + + + Tested Environment + + +This driver is developed on the following hardware + + + + + +Intel Celeron 500 with SiS 630 (rev 02) chipset + + + + + +SiS 900 (rev 01) and SiS 7016/7014 Fast Ethernet Card + + + + + +and tested with these software environments + + + + + +Red Hat Linux version 6.2 + + + + + +Linux kernel version 2.4.0 + + + + + +Netscape version 4.6 + + + + + +NcFTP 3.0.0 beta 18 + + + + + +Samba version 2.0.3 + + + + + + + + + + +Files in This Package + + +In the package you can find these files: + + + + + + +sis900.c + + +Driver source file in C + + + + + +sis900.h + + +Header file for sis900.c + + + + + +sis900.sgml + + +DocBook SGML source of the document + + + + + +sis900.txt + + +Driver document in plain text + + + + + + + + + + Installation + + +Silicon Integrated System Corp. is cooperating closely with core Linux Kernel +developers. The revisions of SiS 900 driver are distributed by the usuall channels +for kernel tar files and patches. Those kernel tar files for official kernel and +patches for kernel pre-release can be download at +official kernel ftp site +and its mirrors. +The 1.06 revision can be found in kernel version later than 2.3.15 and pre-2.2.14, +and 1.07 revision can be found in kernel version 2.4.0. +If you have no prior experience in networking under Linux, please read +Ethernet HOWTO and +Networking HOWTO available from +Linux Documentation Project (LDP). + + + +The driver is bundled in release later than 2.2.11 and 2.3.15 so this +is the most easy case. +Be sure you have the appropriate packages for compiling kernel source. +Those packages are listed in Document/Changes in kernel source +distribution. If you have to install the driver other than those bundled +in kernel release, you should have your driver file +sis900.c and sis900.h +copied into /usr/src/linux/drivers/net/ first. +There are two alternative ways to install the driver + + + +Building the driver as loadable module + + +To build the driver as a loadable kernel module you have to reconfigure +the kernel to activate network support by + + + +make menuconfig + + + +Choose Loadable module support --->, +then select Enable loadable module support. + + + +Choose Network Device Support --->, select +Ethernet (10 or 100Mbit). +Then select EISA, VLB, PCI and on board controllers, +and choose SiS 900/7016 PCI Fast Ethernet Adapter support +to M. + + + +After reconfiguring the kernel, you can make the driver module by + + + +make modules + + + +The driver should be compiled with no errors. After compiling the driver, +the driver can be installed to proper place by + + + +make modules_install + + + +Load the driver into kernel by + + + +insmod sis900 + + + +When loading the driver into memory, some information message can be view by + + + + +dmesg + + +or + + +cat /var/log/message + + + + +If the driver is loaded properly you will have messages similar to this: + + + +sis900.c: v1.07.06 11/07/2000 +eth0: SiS 900 PCI Fast Ethernet at 0xd000, IRQ 10, 00:00:e8:83:7f:a4. +eth0: SiS 900 Internal MII PHY transceiver found at address 1. +eth0: Using SiS 900 Internal MII PHY as default + + + +showing the version of the driver and the results of probing routine. + + + +Once the driver is loaded, network can be brought up by + + + +/sbin/ifconfig eth0 IPADDR broadcast BROADCAST netmask NETMASK media TYPE + + + +where IPADDR, BROADCAST, NETMASK are your IP address, broadcast address and +netmask respectively. TYPE is used to set medium type used by the device. +Typical values are "10baseT"(twisted-pair 10Mbps Ethernet) or "100baseT" +(twisted-pair 100Mbps Ethernet). For more information on how to configure +network interface, please refer to +Networking HOWTO. + + + +The link status is also shown by kernel messages. For example, after the +network interface is activated, you may have the message: + + + +eth0: Media Link On 100mbps full-duplex + + + +If you try to unplug the twist pair (TP) cable you will get + + + +eth0: Media Link Off + + + +indicating that the link is failed. + + + + +Building the driver into kernel + + +If you want to make the driver into kernel, choose Y +rather than M on +SiS 900/7016 PCI Fast Ethernet Adapter support +when configuring the kernel. Build the kernel image in the usual way + + + +make dep + +make clean + +make bzlilo + + + +Next time the system reboot, you have the driver in memory. + + + + + + + Known Problems and Bugs + + +There are some known problems and bugs. If you find any other bugs please +mail to lcchang@sis.com.tw + + + + + +AM79C901 HomePNA PHY is not thoroughly tested, there may be some +bugs in the on the fly change of transceiver. + + + + + +A bug is hidden somewhere in the receive buffer management code, +the bug causes NULL pointer reference in the kernel. This fault is +caught before bad things happen and reported with the message: + + +eth0: NULL pointer encountered in Rx ring, skipping + + +which can be viewed with dmesg or +cat /var/log/message. + + + + + +The media type change from 10Mbps to 100Mbps twisted-pair ethernet +by ifconfig causes the media link down. + + + + + + + + + Revision History + + + + + + +November 13, 2000, Revision 1.07, seventh release, 630E problem fixed +and furthur clean up. + + + + + +November 4, 1999, Revision 1.06, Second release, lots of clean up +and optimization. + + + + + +August 8, 1999, Revision 1.05, Initial Public Release + + + + + + + + + Acknowledgements + + +This driver was originally derived form +Donald Becker's +pci-skeleton and +rtl8139 drivers. Donald also provided various suggestion +regarded with improvements made in revision 1.06. + + + +The 1.05 revision was created by +Jim Huang, AMD 79c901 +support was added by Chin-Shan Li. + + + + +List of Functions +!Idrivers/net/sis900.c + + + diff -u --recursive --new-file v2.4.0-test12/linux/Documentation/devices.txt linux/Documentation/devices.txt --- v2.4.0-test12/linux/Documentation/devices.txt Thu Mar 23 23:32:47 2000 +++ linux/Documentation/devices.txt Sat Dec 30 11:26:10 2000 @@ -1,7 +1,7 @@ LINUX ALLOCATED DEVICES - Maintained by H. Peter Anvin + Maintained by H. Peter Anvin - Last revised: March 23, 2000 + Last revised: December 29, 2000 This list is the Linux Device List, the official registry of allocated device numbers and /dev directory nodes for the Linux operating @@ -36,7 +36,7 @@ reply. - **** PLEASE READ THIS BEFORE SUBMITTING A DEVICE ENTRY **** + **** DEVICE DRIVERS AUTHORS PLEASE READ THIS **** To have a major number allocated, or a minor number in situations where that applies (e.g. busmice), please contact me with the @@ -44,24 +44,32 @@ information regarding any of the devices listed below, or if I have made a mistake, I would greatly appreciate a note. -I do, however, make two requests about the nature of your report. +I do, however, make a few requests about the nature of your report. This is necessary for me to be able to keep this list up to date and -correct in a timely manner. First of all, *please* include the word -"device" in the subject so your mail won't accidentally get buried! I -receive hundreds of email messages a day, so mail sent with other -subjects may very well get lost in the avalanche. +correct in a timely manner. First of all, *please* send it to the +correct address... . I receive hundreds of email +messages a day, so mail sent to other addresses may very well get lost +in the avalanche. Please put in a descriptive subject, so I can find +your mail again should I need to. Too many people send me email +saying just "device number request" in the subject. Second, please include a description of the device *in the same format as this list*. The reason for this is that it is the only way I have found to ensure I have all the requisite information to publish your device and avoid conflicts. +Third, please don't assume that the distributed version of the list is +up to date. Due to the number of registrations I have to maintain it +in "batch mode", so there is likely additional registrations that +haven't been listed yet. + Finally, sometimes I have to play "namespace police." Please don't be offended. I often get submissions for /dev names that would be bound to cause conflicts down the road. I am trying to avoid getting in a situation where we would have to suffer an incompatible forward -change. - +change. Therefore, please consult with me *before* you make your +device names and numbers in any way public, at least to the point +where it would be at all difficult to get them changed. Your cooperation is appreciated. @@ -79,16 +87,18 @@ 7 = /dev/full Returns ENOSPC on write 8 = /dev/random Nondeterministic random number gen. 9 = /dev/urandom Faster, less secure random number gen. + 10 = /dev/aio Asyncronous I/O notification interface block RAM disk 0 = /dev/ram0 First RAM disk + 1 = /dev/ram1 Second RAM disk ... - 7 = /dev/ram7 Eighth RAM disk - 250 = /dev/initrd Initial RAM disk + 250 = /dev/initrd Initial RAM disk {2.6} Older kernels had /dev/ramdisk (1, 1) here. /dev/initrd refers to a RAM disk which was preloaded - by the boot loader. - + by the boot loader; newer kernels use /dev/ram0 for + the initrd. + 2 char Pseudo-TTY masters 0 = /dev/ptyp0 First PTY master 1 = /dev/ptyp1 Second PTY master @@ -199,6 +209,8 @@ ... 255 = /dev/ttyS191 192nd UART serial port + UART serial ports refer to 8250/16450/16550 series devices. + Older versions of the Linux kernel used this major number for BSD PTY devices. As of Linux 2.1.115, this is no longer supported. Use major numbers 2 and 3. @@ -310,6 +322,8 @@ 10 = /dev/adbmouse Apple Desktop Bus mouse 11 = /dev/vrtpanel Vr41xx embedded touch panel 13 = /dev/vpcmouse Connectix Virtual PC Mouse + 14 = /dev/touchscreen/ucb1x00 UCB 1x00 touchscreen + 15 = /dev/touchscreen/mk712 MK712 touchscreen 128 = /dev/beep Fancy beep device 129 = /dev/modreq Kernel module load request {2.6} 130 = /dev/watchdog Watchdog timer port @@ -321,7 +335,7 @@ 139 = /dev/openprom SPARC OpenBoot PROM 140 = /dev/relay8 Berkshire Products Octal relay card 141 = /dev/relay16 Berkshire Products ISO-16 relay card - 142 = /dev/msr x86 model-specific registers + 142 = /dev/msr x86 model-specific registers {2.6} 143 = /dev/pciconf PCI configuration space 144 = /dev/nvram Non-volatile configuration RAM 145 = /dev/hfmodem Soundcard shortwave modem control {2.6} @@ -363,6 +377,26 @@ 182 = /dev/perfctr Performance-monitoring counters 183 = /dev/intel_rng Intel i8x0 random number generator 184 = /dev/cpu/microcode CPU microcode update interface + 186 = /dev/atomicps Atomic shapshot of process state data + 187 = /dev/irnet IrNET device + 188 = /dev/smbusbios SMBus BIOS + 189 = /dev/ussp_ctl User space serial port control + 190 = /dev/crash Mission Critical Linux crash dump facility + 191 = /dev/pcl181 + 192 = /dev/nas_xbus NAS xbus LCD/buttons access + 193 = /dev/d7s SPARC 7-segment display + 194 = /dev/zkshim Zero-Knowledge network shim control + 195 = /dev/elographics/e2201 Elographics touchscreen E271-2201 + 198 = /dev/sexec Signed executable interface + 199 = /dev/scanners/cuecat :CueCat barcode scanner + 200 = /dev/net/tun TAP/TUN network device + 201 = /dev/button/gulpb Transmeta GULP-B buttons + 204 = /dev/video/em8300 EM8300 DVD decoder control + 205 = /dev/video/em8300_mv EM8300 DVD decoder video + 206 = /dev/video/em8300_ma EM8300 DVD decoder audio + 207 = /dev/video/em8300_sp EM8300 DVD decoder subpicture + 208 = /dev/compaq/cpqphpc Compaq PCI Hot Plug Controller + 209 = /dev/compaq/cpqrid Compaq Remote Insight Driver 240-255 Reserved for local use 11 char Raw keyboard device @@ -901,29 +935,62 @@ 0 = /dev/ttyL0 First RISCom port 1 = /dev/ttyL1 Second RISCom port ... - block Reserved for Mylex DAC960 PCI RAID controller + block Mylex DAC960 PCI RAID controller; first controller + 0 = /dev/rd/c0d0 First disk, whole disk + 8 = /dev/rd/c0d1 Second disk, whole disk + ... + 248 = /dev/rd/c0d15 16th disk, whole disk + + For partitions add: + 0 = /dev/rd/c?d? Whole disk + 1 = /dev/rd/c?d?p1 First partition + ... + 7 = /dev/rd/c?d?p7 Seventh partition 49 char SDL RISCom serial card - alternate devices 0 = /dev/cul0 Callout device for ttyL0 1 = /dev/cul1 Callout device for ttyL1 ... - block Reserved for Mylex DAC960 PCI RAID controller + block Mylex DAC960 PCI RAID controller; second controller + 0 = /dev/rd/c1d0 First disk, whole disk + 8 = /dev/rd/c1d1 Second disk, whole disk + ... + 248 = /dev/rd/c1d15 16th disk, whole disk + + Partitions are handled as for major 48. 50 char Reserved for GLINT - block Reserved for Mylex DAC960 PCI RAID controller + + block Mylex DAC960 PCI RAID controller; third controller + 0 = /dev/rd/c2d0 First disk, whole disk + 8 = /dev/rd/c2d1 Second disk, whole disk + ... + 248 = /dev/rd/c2d15 16th disk, whole disk 51 char Baycom radio modem 0 = /dev/bc0 First Baycom radio modem 1 = /dev/bc1 Second Baycom radio modem ... - block Reserved for Mylex DAC960 PCI RAID controller + block Mylex DAC960 PCI RAID controller; fourth controller + 0 = /dev/rd/c3d0 First disk, whole disk + 8 = /dev/rd/c3d1 Second disk, whole disk + ... + 248 = /dev/rd/c3d15 16th disk, whole disk + + Partitions are handled as for major 48. 52 char Spellcaster DataComm/BRI ISDN card 0 = /dev/dcbri0 First DataComm card 1 = /dev/dcbri1 Second DataComm card 2 = /dev/dcbri2 Third DataComm card 3 = /dev/dcbri3 Fourth DataComm card - block Reserved for Mylex DAC960 PCI RAID controller + block Mylex DAC960 PCI RAID controller; fifth controller + 0 = /dev/rd/c4d0 First disk, whole disk + 8 = /dev/rd/c4d1 Second disk, whole disk + ... + 248 = /dev/rd/c4d15 16th disk, whole disk + + Partitions are handled as for major 48. 53 char BDM interface for remote debugging MC683xx microcontrollers 0 = /dev/pd_bdm0 PD BDM interface on lp0 @@ -939,7 +1006,13 @@ Domain Interface and ICD is the commercial interface by P&E. - block Reserved for Mylex DAC960 PCI RAID controller + block Mylex DAC960 PCI RAID controller; sixth controller + 0 = /dev/rd/c5d0 First disk, whole disk + 8 = /dev/rd/c5d1 Second disk, whole disk + ... + 248 = /dev/rd/c5d15 16th disk, whole disk + + Partitions are handled as for major 48. 54 char Electrocardiognosis Holter serial card 0 = /dev/holter0 First Holter port @@ -950,11 +1023,23 @@ to transfer data from Holter 24-hour heart monitoring equipment. - block Reserved for Mylex DAC960 PCI RAID controller + block Mylex DAC960 PCI RAID controller; seventh controller + 0 = /dev/rd/c6d0 First disk, whole disk + 8 = /dev/rd/c6d1 Second disk, whole disk + ... + 248 = /dev/rd/c6d15 16th disk, whole disk + + Partitions are handled as for major 48. 55 char DSP56001 digital signal processor 0 = /dev/dsp56k First DSP56001 - block Reserved for Mylex DAC960 PCI RAID controller + block Mylex DAC960 PCI RAID controller; eigth controller + 0 = /dev/rd/c7d0 First disk, whole disk + 8 = /dev/rd/c7d1 Second disk, whole disk + ... + 248 = /dev/rd/c7d15 16th disk, whole disk + + Partitions are handled as for major 48. 56 char Apple Desktop Bus 0 = /dev/adb ADB bus control @@ -1001,6 +1086,8 @@ running small fs translation drivers) through serial / IRDA / parallel links. + NAMING CONFLICT -- PROPOSED REVISED NAME /dev/rpda0 etc + 60-63 LOCAL/EXPERIMENTAL USE Allocated for local/experimental use. For devices not assigned official numbers, these ranges should be @@ -1175,6 +1262,16 @@ ... 255 = /dev/cuf255 Callout device for ttyF255 + block Compaq Intelligent Drive Array, first controller + 0 = /dev/ida/c0d0 First logical drive whole disk + 16 = /dev/ida/c0d1 Second logical drive whole disk + ... + 240 = /dev/ida/c0d15 16th logical drive whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + 73 char Computone IntelliPort II serial card - control devices 0 = /dev/ip2ipl0 Loadware device for board 0 1 = /dev/ip2stat0 Status device for board 0 @@ -1185,6 +1282,16 @@ 12 = /dev/ip2ipl3 Loadware device for board 3 13 = /dev/ip2stat3 Status device for board 3 + block Compaq Intelligent Drive Array, second controller + 0 = /dev/ida/c1d0 First logical drive whole disk + 16 = /dev/ida/c1d1 Second logical drive whole disk + ... + 240 = /dev/ida/c1d15 16th logical drive whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + 74 char SCI bridge 0 = /dev/SCI/0 SCI device 0 1 = /dev/SCI/1 SCI device 1 @@ -1193,6 +1300,16 @@ Currently for Dolphin Interconnect Solutions' PCI-SCI bridge. + block Compaq Intelligent Drive Array, third controller + 0 = /dev/ida/c2d0 First logical drive whole disk + 16 = /dev/ida/c2d1 Second logical drive whole disk + ... + 240 = /dev/ida/c2d15 16th logical drive whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + 75 char Specialix IO8+ serial card 0 = /dev/ttyW0 First IO8+ port, first card 1 = /dev/ttyW1 Second IO8+ port, first card @@ -1200,6 +1317,16 @@ 8 = /dev/ttyW8 First IO8+ port, second card ... + block Compaq Intelligent Drive Array, fourth controller + 0 = /dev/ida/c3d0 First logical drive whole disk + 16 = /dev/ida/c3d1 Second logical drive whole disk + ... + 240 = /dev/ida/c3d15 16th logical drive whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + 76 char Specialix IO8+ serial card - alternate devices 0 = /dev/cuw0 Callout device for ttyW0 1 = /dev/cuw1 Callout device for ttyW1 @@ -1207,19 +1334,63 @@ 8 = /dev/cuw8 Callout device for ttyW8 ... + block Compaq Intelligent Drive Array, fifth controller + 0 = /dev/ida/c4d0 First logical drive whole disk + 16 = /dev/ida/c4d1 Second logical drive whole disk + ... + 240 = /dev/ida/c4d15 16th logical drive whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + + 77 char ComScire Quantum Noise Generator 0 = /dev/qng ComScire Quantum Noise Generator + block Compaq Intelligent Drive Array, sixth controller + 0 = /dev/ida/c5d0 First logical drive whole disk + 16 = /dev/ida/c5d1 Second logical drive whole disk + ... + 240 = /dev/ida/c5d15 16th logical drive whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + + 78 char PAM Software's multimodem boards 0 = /dev/ttyM0 First PAM modem 1 = /dev/ttyM1 Second PAM modem ... + block Compaq Intelligent Drive Array, seventh controller + 0 = /dev/ida/c6d0 First logical drive whole disk + 16 = /dev/ida/c6d1 Second logical drive whole disk + ... + 240 = /dev/ida/c6d15 16th logical drive whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + + 79 char PAM Software's multimodem boards - alternate devices 0 = /dev/cum0 Callout device for ttyM0 1 = /dev/cum1 Callout device for ttyM1 ... + block Compaq Intelligent Drive Array, eigth controller + 0 = /dev/ida/c7d0 First logical drive whole disk + 16 = /dev/ida/c7d1 Second logical drive whole disk + ... + 240 = /dev/ida/c715 16th logical drive whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + + 80 char Photometrics AT200 CCD camera 0 = /dev/at200 Photometrics AT200 CCD camera @@ -1496,14 +1667,13 @@ 1 = /dev/parport1 Second parallel port ... -100 char POTS (analogue telephone) A/B port {2.6} - 0 = /dev/phone0 First telephone port - 1 = /dev/phone1 Second telephone port - ... + block JavaStation flash disk + 0 = /dev/jsfd JavaStation flash disk - The names have been reallocated to Telephony For - Linux, major 159. All use of major 100 should be - considered legacy and deprecated. +100 char Telephony for Linux + 0 = /dev/phone0 First telephony device + 1 = /dev/phone1 Second telephony device + ... 101 char Motorola DSP 56xxx board 0 = /dev/mdspstat Status information @@ -1511,6 +1681,19 @@ ... 16 = /dev/mdsp16 16th DSP board I/O controls + block AMI HyperDisk RAID controller + 0 = /dev/amiraid/ar0 First array whole disk + 16 = /dev/amiraid/ar1 Second array whole disk + ... + 240 = /dev/amiraid/ar15 16th array whole disk + + For each device, partitions are added as: + 0 = /dev/amiraid/ar? Whole disk + 1 = /dev/amiraid/ar?p1 First partition + 2 = /dev/amiraid/ar?p2 Second partition + ... + 15 = /dev/amiraid/ar?p15 15th partition + 102 char Philips SAA5249 Teletext signal decoder {2.6} 0 = /dev/tlk0 First Teletext decoder 1 = /dev/tlk1 Second Teletext decoder @@ -1527,36 +1710,119 @@ to the arla announce mailing list by sending a mail to . + block Audit device + 0 = /dev/audit Audit device + 104 char Flash BIOS support + block Compaq Next Generation Drive Array, first controller + 0 = /dev/cciss/c0d0 First logical drive, whole disk + 16 = /dev/cciss/c0d1 Second logical drive, whole disk + ... + 240 = /dev/cciss/c0d15 16th logical drive, whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + 105 char Comtrol VS-1000 serial controller 0 = /dev/ttyV0 First VS-1000 port 1 = /dev/ttyV1 Second VS-1000 port ... + block Compaq Next Generation Drive Array, second controller + 0 = /dev/cciss/c1d0 First logical drive, whole disk + 16 = /dev/cciss/c1d1 Second logical drive, whole disk + ... + 240 = /dev/cciss/c1d15 16th logical drive, whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + 106 char Comtrol VS-1000 serial controller - alternate devices 0 = /dev/cuv0 First VS-1000 port 1 = /dev/cuv1 Second VS-1000 port ... + block Compaq Next Generation Drive Array, third controller + 0 = /dev/cciss/c2d0 First logical drive, whole disk + 16 = /dev/cciss/c2d1 Second logical drive, whole disk + ... + 240 = /dev/cciss/c2d15 16th logical drive, whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + 107 char 3Dfx Voodoo Graphics device 0 = /dev/3dfx Primary 3Dfx graphics device + block Compaq Next Generation Drive Array, fourth controller + 0 = /dev/cciss/c3d0 First logical drive, whole disk + 16 = /dev/cciss/c3d1 Second logical drive, whole disk + ... + 240 = /dev/cciss/c3d15 16th logical drive, whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + 108 char Device independent PPP interface 0 = /dev/ppp Device independent PPP interface + block Compaq Next Generation Drive Array, fifth controller + 0 = /dev/cciss/c4d0 First logical drive, whole disk + 16 = /dev/cciss/c4d1 Second logical drive, whole disk + ... + 240 = /dev/cciss/c4d15 16th logical drive, whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + 109 char Reserved for logical volume manager + block Compaq Next Generation Drive Array, sixth controller + 0 = /dev/cciss/c5d0 First logical drive, whole disk + 16 = /dev/cciss/c5d1 Second logical drive, whole disk + ... + 240 = /dev/cciss/c5d15 16th logical drive, whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + 110 char miroMEDIA Surround board 0 = /dev/srnd0 First miroMEDIA Surround board 1 = /dev/srnd1 Second miroMEDIA Surround board ... + block Compaq Next Generation Drive Array, seventh controller + 0 = /dev/cciss/c6d0 First logical drive, whole disk + 16 = /dev/cciss/c6d1 Second logical drive, whole disk + ... + 240 = /dev/cciss/c6d15 16th logical drive, whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + 111 char Philips SAA7146-based audio/video card {2.6} 0 = /dev/av0 First A/V card 1 = /dev/av1 Second A/V card ... + block Compaq Next Generation Drive Array, eigth controller + 0 = /dev/cciss/c7d0 First logical drive, whole disk + 16 = /dev/cciss/c7d1 Second logical drive, whole disk + ... + 240 = /dev/cciss/c7d15 16th logical drive, whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + 112 char ISI serial card 0 = /dev/ttyM0 First ISI port 1 = /dev/ttyM1 Second ISI port @@ -1717,10 +1983,7 @@ 1 = /dev/gfax1 GammaLink channel 1 ... -159 char Telephony for Linux - 0 = /dev/phone0 First telephony device - 1 = /dev/phone1 Second telephony device - ... +159 RESERVED 160 char General Purpose Instrument Bus (GPIB) 0 = /dev/gpib0 First GPIB bus @@ -1944,7 +2207,244 @@ 240 = /dev/mvideo/status15 16th device ... -195-239 UNALLOCATED +195 char Nvidia graphics devices + 0 = /dev/nvidia0 First Nvidia card + 1 = /dev/nvidia1 Second Nvidia card + ... + 255 = /dev/nvidiactl Nvidia card control device + +196-197 UNASSIGNED + +198 char Total Impact TPMP2 quad coprocessor PCI card + 0 = /dev/tpmp2/0 First card + 1 = /dev/tpmp2/1 Second card + ... + +199 char Veritas volume manager (VxVM) volumes + 0 = /dev/vx/rdsk/*/* First volume + 1 = /dev/vx/rdsk/*/* Second volume + ... + block Veritas volume manager (VxVM) volumes + 0 = /dev/vx/dsk/*/* First volume + 1 = /dev/vx/dsk/*/* First volume + ... + + The namespace in these directories is maintained by + the user space VxVM software. + +200 char Veritas VxVM configuration interface + 0 = /dev/vx/config Configuration access node + 1 = /dev/vx/trace Volume i/o trace access node + 2 = /dev/vx/iod Volume i/o daemon access node + 3 = /dev/vx/info Volume information access node + 4 = /dev/vx/task Volume tasks access node + 5 = /dev/vx/taskmon Volume tasks monitor daemon + +201 char Veritas VxVM dynamic multipathing driver + 0 = /dev/vx/rdmp/* First multipath device + 1 = /dev/vx/rdmp/* Second multipath device + ... + block Veritas VxVM dynamic multipathing driver + 0 = /dev/vx/dmp/* First multipath device + 1 = /dev/vx/dmp/* Second multipath device + ... + + The namespace in these directories is maintained by + the user space VxVM software. + +202 char CPU model-specific registers + 0 = /dev/cpu/0/msr MSRs on CPU 0 + 1 = /dev/cpu/1/msr MSRs on CPU 1 + ... + +203 char CPU CPUID information + 0 = /dev/cpu/0/cpuid CPUID on CPU 0 + 1 = /dev/cpu/1/cpuid CPUID on CPU 1 + ... + +204 char Low-density serial ports + 0 = /dev/ttyLU0 LinkUp Systems L72xx UART - port 0 + 1 = /dev/ttyLU1 LinkUp Systems L72xx UART - port 1 + 2 = /dev/ttyLU2 LinkUp Systems L72xx UART - port 2 + 3 = /dev/ttyLU3 LinkUp Systems L72xx UART - port 3 + 4 = /dev/ttyFB0 Intel Footbridge (ARM) + 5 = /dev/ttySA0 StrongARM builtin serial port 0 + 6 = /dev/ttySA1 StrongARM builtin serial port 1 + 7 = /dev/ttySA2 StrongARM builtin serial port 2 + 8 = /dev/ttySC0 SCI serial port (SuperH) - port 0 + 9 = /dev/ttySC1 SCI serial port (SuperH) - port 1 + 10 = /dev/ttySC2 SCI serial port (SuperH) - port 2 + 11 = /dev/ttySC3 SCI serial port (SuperH) - port 3 + 12 = /dev/ttyFW0 Firmware console - port 0 + 13 = /dev/ttyFW1 Firmware console - port 1 + 14 = /dev/ttyFW2 Firmware console - port 2 + 15 = /dev/ttyFW3 Firmware console - port 3 + 16 = /dev/ttyAM0 ARM "AMBA" serial port 0 + ... + 31 = /dev/ttyAM15 ARM "AMBA" serial port 15 + +205 char Low-density serial ports (alternate device) + 0 = /dev/culu0 Callout device for ttyLU0 + 1 = /dev/culu1 Callout device for ttyLU1 + 2 = /dev/culu2 Callout device for ttyLU2 + 3 = /dev/culu3 Callout device for ttyLU3 + 4 = /dev/cufb0 Callout device for ttyFB0 + 5 = /dev/cusa0 Callout device for ttySA0 + 6 = /dev/cusa1 Callout device for ttySA1 + 7 = /dev/cusa2 Callout device for ttySA2 + 8 = /dev/cusc0 Callout device for ttySC0 + 9 = /dev/cusc1 Callout device for ttySC1 + 10 = /dev/cusc2 Callout device for ttySC2 + 11 = /dev/cusc3 Callout device for ttySC3 + 12 = /dev/cufw0 Callout device for ttyFW0 + 13 = /dev/cufw1 Callout device for ttyFW1 + 14 = /dev/cufw2 Callout device for ttyFW2 + 15 = /dev/cufw3 Callout device for ttyFW3 + 16 = /dev/cuam0 Callout device for ttyAM0 + ... + 31 = /dev/cuam15 Callout device for ttyAM15 + +206 char OnStream SC-x0 tape devices + 0 = /dev/osst0 First OnStream SCSI tape, mode 0 + 1 = /dev/osst1 Second OnStream SCSI tape, mode 0 + ... + 32 = /dev/osst0l First OnStream SCSI tape, mode 1 + 33 = /dev/osst1l Second OnStream SCSI tape, mode 1 + ... + 64 = /dev/osst0m First OnStream SCSI tape, mode 2 + 65 = /dev/osst1m Second OnStream SCSI tape, mode 2 + ... + 96 = /dev/osst0a First OnStream SCSI tape, mode 3 + 97 = /dev/osst1a Second OnStream SCSI tape, mode 3 + ... + 128 = /dev/nosst0 No rewind version of /dev/osst0 + 129 = /dev/nosst1 No rewind version of /dev/osst1 + ... + 160 = /dev/nosst0l No rewind version of /dev/osst0l + 161 = /dev/nosst1l No rewind version of /dev/osst1l + ... + 192 = /dev/nosst0m No rewind version of /dev/osst0m + 193 = /dev/nosst1m No rewind version of /dev/osst1m + ... + 224 = /dev/nosst0a No rewind version of /dev/osst0a + 225 = /dev/nosst1a No rewind version of /dev/osst1a + ... + + The OnStream SC-x0 SCSI tapes do not support the + standard SCSI SASD command set and therefore need + their own driver "osst". Note that the IDE, USB (and + maybe ParPort) versions may be driven via ide-scsi or + usb-storage SCSI emulation and this osst device and + driver as well. The ADR-x0 drives are QIC-157 + compliant and don't need osst. + +207 char Compaq ProLiant health feature indicate + 0 = /dev/cpqhealth/cpqw Redirector interface + 1 = /dev/cpqhealth/crom EISA CROM + 2 = /dev/cpqhealth/cdt Data Table + 3 = /dev/cpqhealth/cevt Event Log + 4 = /dev/cpqhealth/casr Automatic Server Recovery + 5 = /dev/cpqhealth/cecc ECC Memory + 6 = /dev/cpqhealth/cmca Machine Check Architecture + 7 = /dev/cpqhealth/ccsm Deprecated CDT + 8 = /dev/cpqhealth/cnmi NMI Handling + 9 = /dev/cpqhealth/css Sideshow Management + 10 = /dev/cpqhealth/cram CMOS interface + 11 = /dev/cpqhealth/cpci PCI IRQ interface + +208 char User space serial ports + 0 = /dev/ttyU0 First user space serial port + 1 = /dev/ttyU1 Second user space serial port + ... + +209 char User space serial ports (alternate devices) + 0 = /dev/cuu0 Callout device for ttyU0 + 1 = /dev/cuu1 Callout device for ttyU1 + ... + +210 char SBE, Inc. sync/async serial card + 0 = /dev/sbei/wxcfg0 Configuration device for board 0 + 1 = /dev/sbei/dld0 Download device for board 0 + 2 = /dev/sbei/wan00 WAN device, port 0, board 0 + 3 = /dev/sbei/wan01 WAN device, port 1, board 0 + 4 = /dev/sbei/wan02 WAN device, port 2, board 0 + 5 = /dev/sbei/wan03 WAN device, port 3, board 0 + 6 = /dev/sbei/wanc00 WAN clone device, port 0, board 0 + 7 = /dev/sbei/wanc01 WAN clone device, port 1, board 0 + 8 = /dev/sbei/wanc02 WAN clone device, port 2, board 0 + 9 = /dev/sbei/wanc03 WAN clone device, port 3, board 0 + 10 = /dev/sbei/wxcfg1 Configuration device for board 1 + 11 = /dev/sbei/dld1 Download device for board 1 + 12 = /dev/sbei/wan10 WAN device, port 0, board 1 + 13 = /dev/sbei/wan11 WAN device, port 1, board 1 + 14 = /dev/sbei/wan12 WAN device, port 2, board 1 + 15 = /dev/sbei/wan13 WAN device, port 3, board 1 + 16 = /dev/sbei/wanc10 WAN clone device, port 0, board 1 + 17 = /dev/sbei/wanc11 WAN clone device, port 1, board 1 + 18 = /dev/sbei/wanc12 WAN clone device, port 2, board 1 + 19 = /dev/sbei/wanc13 WAN clone device, port 3, board 1 + ... + + Yes, each board is really spaced 10 (decimal) apart. + +211 char Addinum CPCI1500 digital I/O card + 0 = /dev/addinum/cpci1500/0 First CPCI1500 card + 1 = /dev/addinum/cpci1500/1 Second CPCI1500 card + ... + +216 char USB BlueTooth devices + 0 = /dev/ttyUB0 First USB BlueTooth device + 1 = /dev/ttyUB1 Second USB BlueTooth device + ... + +217 char USB BlueTooth devices (alternate devices) + 0 = /dev/cuub0 Callout device for ttyUB0 + 1 = /dev/cuub1 Callout device for ttyUB1 + ... + +218 char The Logical Company bus Unibus/Qbus adapters + 0 = /dev/logicalco/bci/0 First bus adapter + 1 = /dev/logicalco/bci/1 First bus adapter + ... + +219 char The Logical Company DCI-1300 digital I/O card + 0 = /dev/logicalco/dci1300/0 First DCI-1300 card + 1 = /dev/logicalco/dci1300/1 Second DCI-1300 card + ... + +220 char Myricom Myrinet "GM" board + 0 = /dev/myricom/gm0 First Myrinet GM board + 1 = /dev/myricom/gmp0 First board "root access" + 2 = /dev/myricom/gm1 Second Myrinet GM board + 3 = /dev/myricom/gmp1 Second board "root access" + ... + +221 char VME bus + 0 = /dev/bus/vme/m0 First master image + 1 = /dev/bus/vme/m1 Second master image + 2 = /dev/bus/vme/m2 Third master image + 3 = /dev/bus/vme/m3 Fourth master image + 4 = /dev/bus/vme/s0 First slave image + 5 = /dev/bus/vme/s1 Second slave image + 6 = /dev/bus/vme/s2 Third slave image + 7 = /dev/bus/vme/s3 Fourth slave image + 8 = /dev/bus/vme/ctl Control + + It is expected that all VME bus drivers will use the + same interface. For interface documentation see + http://www.vmelinux.org/. + +224 char A2232 serial card + 0 = /dev/ttyY0 First A2232 port + 1 = /dev/cuy0 Second A2232 port + ... + +225 char A2232 serial card (alternate devices) + 0 = /dev/cuy0 Callout device for ttyY0 + 1 = /dev/cuy1 Callout device for ttyY1 + ... + +226-239 UNASSIGNED 240-254 LOCAL/EXPERIMENTAL USE @@ -2025,6 +2525,14 @@ /dev/log socket syslog local socket /dev/gpmdata socket gpm mouse multiplexer + Mount points + +The following names are reserved for mounting special filesystems +under /dev. These special filesystems provide kernel interfaces that +cannot be provided with standard device nodes. + +/dev/pts devpts PTY slave filesystem +/dev/shm shmfs POSIX shared memory maintenance access **** TERMINAL DEVICES diff -u --recursive --new-file v2.4.0-test12/linux/Documentation/i2c/functionality linux/Documentation/i2c/functionality --- v2.4.0-test12/linux/Documentation/i2c/functionality Wed Dec 31 16:00:00 1969 +++ linux/Documentation/i2c/functionality Fri Dec 29 14:35:47 2000 @@ -0,0 +1,135 @@ +INTRODUCTION +------------ + +Because not every I2C or SMBus adapter implements everything in the +I2C specifications, a client can not trust that everything it needs +is implemented when it is given the option to attach to an adapter: +the client needs some way to check whether an adapter has the needed +functionality. + + +FUNCTIONALITY CONSTANTS +----------------------- + +For the most up-to-date list of functionality constants, please check +! + + I2C_FUNC_I2C Plain i2c-level commands (Pure SMBus + adapters typically can not do these) + I2C_FUNC_10BIT_ADDR Handles the 10-bit address extensions + I2C_FUNC_PROTOCOL_MANGLING Knows about the I2C_M_REV_DIR_ADDR, + I2C_M_REV_DIR_ADDR and I2C_M_REV_DIR_NOSTART + flags (which modify the i2c protocol!) + I2C_FUNC_SMBUS_QUICK Handles the SMBus write_quick command + I2C_FUNC_SMBUS_READ_BYTE Handles the SMBus read_byte command + I2C_FUNC_SMBUS_WRITE_BYTE Handles the SMBus write_byte command + I2C_FUNC_SMBUS_READ_BYTE_DATA Handles the SMBus read_byte_data command + I2C_FUNC_SMBUS_WRITE_BYTE_DATA Handles the SMBus write_byte_data command + I2C_FUNC_SMBUS_READ_WORD_DATA Handles the SMBus read_word_data command + I2C_FUNC_SMBUS_WRITE_WORD_DATA Handles the SMBus write_byte_data command + I2C_FUNC_SMBUS_PROC_CALL Handles the SMBus process_call command + I2C_FUNC_SMBUS_READ_BLOCK_DATA Handles the SMBus read_block_data command + I2C_FUNC_SMBUS_WRITE_BLOCK_DATA Handles the SMBus write_block_data command + I2C_FUNC_SMBUS_READ_I2C_BLOCK Handles the SMBus read_i2c_block_data command + I2C_FUNC_SMBUS_WRITE_I2C_BLOCK Handles the SMBus write_i2c_block_data command + +A few combinations of the above flags are also defined for your convenience: + + I2C_FUNC_SMBUS_BYTE Handles the SMBus read_byte + and write_byte commands + I2C_FUNC_SMBUS_BYTE_DATA Handles the SMBus read_byte_data + and write_byte_data commands + I2C_FUNC_SMBUS_WORD_DATA Handles the SMBus read_word_data + and write_word_data commands + I2C_FUNC_SMBUS_BLOCK_DATA Handles the SMBus read_block_data + and write_block_data commands + I2C_FUNC_SMBUS_I2C_BLOCK Handles the SMBus read_i2c_block_data + and write_i2c_block_data commands + I2C_FUNC_SMBUS_EMUL Handles all SMBus commands than can be + emulated by a real I2C adapter (using + the transparent emulation layer) + + +ALGORITHM/ADAPTER IMPLEMENTATION +-------------------------------- + +When you write a new algorithm driver, you will have to implement a +function callback `functionality', that gets an i2c_adapter structure +pointer as its only parameter: + + struct i2c_algorithm { + /* Many other things of course; check ! */ + u32 (*functionality) (struct i2c_adapter *); + } + +A typically implementation is given below, from i2c-algo-bit.c: + + static u32 bit_func(struct i2c_adapter *adap) + { + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | + I2C_FUNC_PROTOCOL_MANGLING; + } + + + +CLIENT CHECKING +--------------- + +Before a client tries to attach to an adapter, or even do tests to check +whether one of the devices it supports is present on an adapter, it should +check whether the needed functionality is present. There are two functions +defined which should be used instead of calling the functionality hook +in the algorithm structure directly: + + /* Return the functionality mask */ + extern u32 i2c_get_functionality (struct i2c_adapter *adap); + + /* Return 1 if adapter supports everything we need, 0 if not. */ + extern int i2c_check_functionality (struct i2c_adapter *adap, u32 func); + +This is a typical way to use these functions (from the writing-clients +document): + int foo_detect_client(struct i2c_adapter *adapter, int address, + unsigned short flags, int kind) + { + /* Define needed variables */ + + /* As the very first action, we check whether the adapter has the + needed functionality: we need the SMBus read_word_data, + write_word_data and write_byte functions in this example. */ + if (!i2c_check_functionality(adapter,I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_WRITE_BYTE)) + goto ERROR0; + + /* Now we can do the real detection */ + + ERROR0: + /* Return an error */ + } + + + +CHECKING THROUGH /DEV +--------------------- + +If you try to access an adapter from a userspace program, you will have +to use the /dev interface. You will still have to check whether the +functionality you need is supported, of course. This is done using +the I2C_FUNCS ioctl. An example, adapted from the lm_sensors i2c_detect +program, is below: + + int file; + if (file = open("/dev/i2c-0",O_RDWR) < 0) { + /* Some kind of error handling */ + exit(1); + } + if (ioctl(file,I2C_FUNCS,&funcs) < 0) { + /* Some kind of error handling */ + exit(1); + } + if (! (funcs & I2C_FUNC_SMBUS_QUICK)) { + /* Oops, the needed functionality (SMBus write_quick function) is + not available! */ + exit(1); + } + /* Now it is safe to use the SMBus write_quick command */ diff -u --recursive --new-file v2.4.0-test12/linux/Documentation/kernel-parameters.txt linux/Documentation/kernel-parameters.txt --- v2.4.0-test12/linux/Documentation/kernel-parameters.txt Tue Sep 5 13:51:14 2000 +++ linux/Documentation/kernel-parameters.txt Sat Dec 30 11:23:13 2000 @@ -43,6 +43,7 @@ SERIAL Serial support is enabled. SMP The kernel is an SMP kernel. SOUND Appropriate sound system support is enabled. + V4L Video For Linux support is enabled. VGA The VGA console has been enabled. VT Virtual terminal support is enabled. XT IBM PC/XT MFM hard disk support is enabled. @@ -115,6 +116,11 @@ Duplex Mode. bmouse= [HW,MOUSE,PS2] Bus mouse. + + bttv.card= [HW,V4L] bttv (bt848 + bt878 based grabber cards), most + bttv.radio= important insmod options are available as kernel args too. + bttv.pll= see Documentation/video4linux/bttv/Insmod-options + bttv.tuner= and Documentation/video4linux/bttv/CARDLIST BusLogic= [HW,SCSI] diff -u --recursive --new-file v2.4.0-test12/linux/Documentation/modules.txt linux/Documentation/modules.txt --- v2.4.0-test12/linux/Documentation/modules.txt Sat Nov 6 10:38:40 1999 +++ linux/Documentation/modules.txt Fri Dec 29 14:35:47 2000 @@ -124,7 +124,7 @@ To use modprobe successfully, you generally place the following command in your /etc/rc.d/rc.S script. (Read more about this in the -"rc.hints" file in the module utilities package, "modules-x.y.z.tar.gz".) +"rc.hints" file in the module utilities package, "modutils-x.y.z.tar.gz".) /sbin/depmod -a diff -u --recursive --new-file v2.4.0-test12/linux/Documentation/networking/sis900.txt linux/Documentation/networking/sis900.txt --- v2.4.0-test12/linux/Documentation/networking/sis900.txt Sun Nov 19 18:44:01 2000 +++ linux/Documentation/networking/sis900.txt Fri Dec 29 14:07:19 2000 @@ -5,14 +5,43 @@ Lei Chun Chang - November 16, 2000. Document Revision: 0.3 + Copyright © 1999 by Silicon Integrated System Corp. This document gives some information on installation and usage of SiS 900/7016 device driver under Linux. - _________________________________________________________________ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA + _________________________________________________________________ + + Table of Contents + 1. Introduction + 2. Changes + 3. Tested Environment + 4. Files in This Package + 5. Installation + + Building the driver as loadable module + Building the driver into kernel + + 6. Known Problems and Bugs + 7. Revision History + 8. Acknowledgements _________________________________________________________________ -Introduction +Chapter 1. Introduction This document describes the revision 1.06 and 1.07 of SiS 900/7016 Fast Ethernet device driver under Linux. The driver is developed by @@ -20,9 +49,8 @@ General Public License (GPL). The driver can be compiled as a loadable module and used under Linux kernel version 2.2.x. (rev. 1.06) With minimal changes, the driver can also be used under 2.3.x and 2.4.x - kernel (rev. 1.07), please see the section called Installation. If you - are intended to use the driver for earlier kernels, you are on your - own. + kernel (rev. 1.07), please see Chapter 5. If you are intended to use + the driver for earlier kernels, you are on your own. The driver is tested with usual TCP/IP applications including FTP, Telnet, Netscape etc. and is used constantly by the developers. @@ -30,27 +58,7 @@ Please send all comments/fixes/questions to Lei-Chun Chang. _________________________________________________________________ -License - - Copyright (C) 1999 Silicon Integrated System Corp. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 U -SA - _________________________________________________________________ - -Changes +Chapter 2. Changes Changes made in Revision 1.07 @@ -75,9 +83,10 @@ rule. 14. Support for ICS1893 10/100 Interated PHYceiver. 15. Support for media select by ifconfig. + 16. Added kernel-doc extratable documentation. _________________________________________________________________ -Tested Environment +Chapter 3. Tested Environment This driver is developed on the following hardware @@ -93,7 +102,7 @@ * Samba version 2.0.3 _________________________________________________________________ -Files in This Package +Chapter 4. Files in This Package In the package you can find these files: @@ -110,7 +119,7 @@ Driver document in plain text _________________________________________________________________ -Installation +Chapter 5. Installation Silicon Integrated System Corp. is cooperating closely with core Linux Kernel developers. The revisions of SiS 900 driver are distributed by @@ -179,11 +188,14 @@ Once the driver is loaded, network can be brought up by -/sbin/ifconfig eth0 IPADDR broadcast BROADCAST netmask NETMASK +/sbin/ifconfig eth0 IPADDR broadcast BROADCAST netmask NETMASK media TYPE where IPADDR, BROADCAST, NETMASK are your IP address, broadcast - address and netmask respectively. For more information on how to - configure network interface, please refer to Networking HOWTO. + address and netmask respectively. TYPE is used to set medium type used + by the device. Typical values are "10baseT"(twisted-pair 10Mbps + Ethernet) or "100baseT" (twisted-pair 100Mbps Ethernet). For more + information on how to configure network interface, please refer to + Networking HOWTO. The link status is also shown by kernel messages. For example, after the network interface is activated, you may have the message: @@ -212,7 +224,7 @@ Next time the system reboot, you have the driver in memory. _________________________________________________________________ -Known Problems and Bugs +Chapter 6. Known Problems and Bugs There are some known problems and bugs. If you find any other bugs please mail to lcchang@sis.com.tw @@ -224,9 +236,11 @@ caught before bad things happen and reported with the message: eth0: NULL pointer encountered in Rx ring, skipping which can be viewed with dmesg or cat /var/log/message. + 3. The media type change from 10Mbps to 100Mbps twisted-pair ethernet + by ifconfig causes the media link down. _________________________________________________________________ -Revision History +Chapter 7. Revision History * November 13, 2000, Revision 1.07, seventh release, 630E problem fixed and furthur clean up. @@ -235,7 +249,7 @@ * August 8, 1999, Revision 1.05, Initial Public Release _________________________________________________________________ -Acknowledgements +Chapter 8. Acknowledgements This driver was originally derived form Donald Becker's pci-skeleton and rtl8139 drivers. Donald also provided various suggestion regarded diff -u --recursive --new-file v2.4.0-test12/linux/Documentation/parport.txt linux/Documentation/parport.txt --- v2.4.0-test12/linux/Documentation/parport.txt Mon Jun 19 17:59:32 2000 +++ linux/Documentation/parport.txt Fri Dec 29 14:07:19 2000 @@ -219,6 +219,46 @@ * IRQ autoprobing works only for a few port types at the moment. +Reporting printer problems with parport +======================================= + +If you are having problems printing, please go through these steps to +try to narrow down where the problem area is. + +When reporting problems with parport, really you need to give all of +the messages that parport_pc spits out when it initialises. There are +several code paths: + +o polling +o interrupt-driven, protocol in software +o interrupt-driven, protocol in hardware using PIO +o interrupt-driven, protocol in hardware using DMA + +The kernel messages that parport_pc logs give an indication of which +code path is being used. (They could be a lot better actually..) + +For normal printer protocol, having IEEE 1284 modes enabled or not +should not make a difference. + +To turn off the 'protocol in hardware' code paths, disable +CONFIG_PARPORT_PC_FIFO. Note that when they are enabled they are not +necessarily _used_; it depends on whether the hardware is available, +enabled by the BIOS, and detected by the driver. + +So, to start with, disable CONFIG_PARPORT_PC_FIFO, and load parport_pc +with 'irq=none'. See if printing works then. It really should, +because this is the simplest code path. + +If that works fine, try with 'io=0x378 irq=7' (adjust for your +hardware), to make it use interrupt-driven in-software protocol. + +If _that_ works fine, then one of the hardware modes isn't working +right. Enable CONFIG_PARPORT_PC_FIFO (no, it isn't a module option, +and yes, it should be), set the port to ECP mode in the BIOS and note +the DMA channel, and try with: + + io=0x378 irq=7 dma=none (for PIO) + io=0x378 irq=7 dma=3 (for DMA) -- Philip.Blundell@pobox.com tim@cyberelk.demon.co.uk diff -u --recursive --new-file v2.4.0-test12/linux/Documentation/sound/ALS linux/Documentation/sound/ALS --- v2.4.0-test12/linux/Documentation/sound/ALS Tue Apr 11 19:13:15 2000 +++ linux/Documentation/sound/ALS Fri Dec 29 14:35:47 2000 @@ -9,25 +9,42 @@ as part of the Sound Blaster 16 driver (adding only 800 bytes to the SB16 driver). -To use an ALS sound card under Linux, enable the following options in the -sound configuration section of the kernel config: +To use an ALS sound card under Linux, enable the following options as +modules in the sound configuration section of the kernel config: - 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support - FM synthesizer (YM3812/OPL-3) support + - standalone MPU401 support may be required for some cards; for the + ALS-007, when using isapnptools, it is required Since the ALS-007/100/200 are PnP cards, ISAPnP support should probably be -compiled in. +compiled in. If kernel level PnP support is not included, isapnptools will +be required to configure the card before the sound modules are loaded. -Alternatively, if you decide not to use kernel level ISAPnP, you can use the -user mode isapnptools to wake up the sound card, as in 2.2.X. Set the "I/O -base for SB", "Sound Blaster IRQ" and "Sound Blaster DMA" (8 bit - -either 0, 1 or 3) to the values used in your particular installation (they -should match the values used to configure the card using isapnp). The -ALS-007 does NOT implement 16 bit DMA, so the "Sound Blaster 16 bit DMA" -should be set to -1. If you wish to use the external MPU-401 interface on -the card, "MPU401 I/O base of SB16" and "SB MPU401 IRQ" should be set to -the appropriate values for your installation. (Note that the ALS-007 -requires a separate IRQ for the MPU-401, so don't specify -1 here). (Note -that the base port of the internal FM synth is fixed at 0x388 on the ALS007; -in any case the FM synth location cannot be set in the kernel configuration). +When using kernel level ISAPnP, the kernel should correctly identify and +configure all resources required by the card when the "sb" module is +inserted. Note that the ALS-007 does not have a 16 bit DMA channel and that +the MPU401 interface on this card uses a different interrupt to the audio +section. This should all be correctly configured by the kernel; if problems +with the MPU401 interface surface, try using the standalone MPU401 module, +passing "0" as the "sb" module's "mpu_io" module parameter to prevent the +soundblaster driver attempting to register the MPU401 itself. The onboard +synth device can be accessed using the "opl3" module. + +If isapnptools is used to wake up the sound card (as in 2.2.x), the settings +of the card's resources should be passed to the kernel modules ("sb", "opl3" +and "mpu401") using the module parameters. When configuring an ALS-007, be +sure to specify different IRQs for the audio and MPU401 sections - this card +requires they be different. For "sb", "io", "irq" and "dma" should be set +to the same values used to configure the audio section of the card with +isapnp. "dma16" should be explicitly set to "-1" for an ALS-007 since this +card does not have a 16 bit dma channel; if not specified the kernel will +default to using channel 5 anyway which will cause audio not to work. +"mpu_io" should be set to 0. The "io" parameter of the "opl3" module should +also agree with the setting used by isapnp. To get the MPU401 interface +working on an ALS-007 card, the "mpu401" module will be required since this +card uses separate IRQs for the audio and MPU401 sections and there is no +parameter available to pass a different IRQ to the "sb" driver (whose +inbuilt MPU401 driver would otherwise be fine). Insert the mpu401 module +passing appropriate values using the "io" and "irq" parameters. The resulting sound driver will provide the following capabilities: - 8 and 16 bit audio playback @@ -45,3 +62,5 @@ Modified 2000-02-26 by Dave Forrest, drf5n@virginia.edu to add ALS100/ALS200 Modified 2000-04-10 by Paul Laufer, pelaufer@csupomona.edu to add ISAPnP info. +Modified 2000-11-19 by Jonathan Woithe, jwoithe@physics.adelaide.edu.au + - updated information for kernel 2.4.x. diff -u --recursive --new-file v2.4.0-test12/linux/Documentation/sound/Soundblaster linux/Documentation/sound/Soundblaster --- v2.4.0-test12/linux/Documentation/sound/Soundblaster Fri Aug 11 14:42:16 2000 +++ linux/Documentation/sound/Soundblaster Sun Dec 31 09:27:57 2000 @@ -24,6 +24,9 @@ multiple=0 Set to disable detection of multiple Soundblaster cards. Consider it a bug if this option is needed, and send in a report. +pnplegacy=1 Set this to be able to use a PnP card(s) along with a single + non-PnP (legacy) card. Above options for io, irq, etc. are + needed, and will apply only to the legacy card. reverse=1 Reverses the order of the search in the PnP table. uart401=1 Set to enable detection of mpu devices on some clones. isapnpjump=n Jumps to slot n in the driver's PnP table. Use the source, diff -u --recursive --new-file v2.4.0-test12/linux/Documentation/video4linux/bttv/Insmod-options linux/Documentation/video4linux/bttv/Insmod-options --- v2.4.0-test12/linux/Documentation/video4linux/bttv/Insmod-options Sun Nov 19 18:44:02 2000 +++ linux/Documentation/video4linux/bttv/Insmod-options Sat Dec 30 11:23:13 2000 @@ -4,6 +4,7 @@ insmod args: card=n card type, see CARDLIST for a list. + tuner=n tuner type, see CARDLIST for a list. radio=0/1 card supports radio pll=0/1/2 pll settings 0: don't use PLL diff -u --recursive --new-file v2.4.0-test12/linux/Documentation/video4linux/bttv/Modules.conf linux/Documentation/video4linux/bttv/Modules.conf --- v2.4.0-test12/linux/Documentation/video4linux/bttv/Modules.conf Thu Dec 16 13:59:38 1999 +++ linux/Documentation/video4linux/bttv/Modules.conf Sat Dec 30 11:23:13 2000 @@ -9,7 +9,3 @@ options bttv card=2 radio=1 options tuner debug=1 -# make alsa + msp3400 play nicely -options snd-card-ens snd_index=0 -options msp3400 mixer=1 - diff -u --recursive --new-file v2.4.0-test12/linux/Documentation/video4linux/bttv/README linux/Documentation/video4linux/bttv/README --- v2.4.0-test12/linux/Documentation/video4linux/bttv/README Sun Nov 19 18:44:02 2000 +++ linux/Documentation/video4linux/bttv/README Sat Dec 30 11:23:13 2000 @@ -31,8 +31,9 @@ ------------ If you are compiling the kernel version, just say 'm' if you are asked -for bttv. I /strongly/ suggest to compile bttv as module, because -there are some insmod options for configuring the driver. +for bttv. I /strongly/ recommend to compile bttv as module, because +there are some insmod options for configuring the driver. Starting +with 0.7.49 the most important ones are available as kernel args too. If you downloaded the separate bttv bundle: You need configured kernel sources to compile the bttv driver. The driver uses some Makefile diff -u --recursive --new-file v2.4.0-test12/linux/MAINTAINERS linux/MAINTAINERS --- v2.4.0-test12/linux/MAINTAINERS Mon Dec 11 17:59:43 2000 +++ linux/MAINTAINERS Sun Dec 31 09:31:15 2000 @@ -316,7 +316,7 @@ DC390/AM53C974 SCSI driver P: Kurt Garloff -M: kurt@garloff.de +M: garloff@suse.de W: http://www.garloff.de/kurt/linux/dc390/ S: Maintained @@ -909,6 +909,13 @@ W: http://www.linuxtr.net S: Maintained +ONSTREAM SCSI TAPE DRIVER +P: Willem Riede +M: osst@riede.org +L: osst@linux1.onstream.nl +L: linux-scsi@vger.rutgers.edu +S: Maintained + OPL3-SA2, SA3, and SAx DRIVER P: Scott Murray M: scott@spiteful.org @@ -1166,7 +1173,7 @@ SUPERH P: Niibe Yutaka -M: gniibe@chroot.org +M: gniibe@m17n.org P: Kazumoto Kojima M: kkojima@rr.iij4u.or.jp L: linux-sh@m17n.org diff -u --recursive --new-file v2.4.0-test12/linux/Makefile linux/Makefile --- v2.4.0-test12/linux/Makefile Mon Dec 11 17:59:43 2000 +++ linux/Makefile Sun Dec 31 11:44:02 2000 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 0 -EXTRAVERSION = -test12 +EXTRAVERSION = -prerelease KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -123,8 +123,7 @@ drivers/char/char.o \ drivers/misc/misc.o \ drivers/net/net.o \ - drivers/media/media.o \ - drivers/parport/parport.a + drivers/media/media.o LIBS =$(TOPDIR)/lib/lib.a SUBDIRS =kernel drivers mm fs net ipc lib @@ -133,6 +132,7 @@ DRIVERS-m := DRIVERS- := +DRIVERS-$(CONFIG_PARPORT) += drivers/parport/driver.o DRIVERS-$(CONFIG_AGP) += drivers/char/agp/agp.o DRIVERS-$(CONFIG_DRM) += drivers/char/drm/drm.o DRIVERS-$(CONFIG_NUBUS) += drivers/nubus/nubus.a @@ -148,18 +148,18 @@ DRIVERS-$(CONFIG_IEEE1394) += drivers/ieee1394/ieee1394.a ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR)$(CONFIG_PARIDE_PCD),) -DRIVERS-y += drivers/cdrom/cdrom.a +DRIVERS-y += drivers/cdrom/driver.o endif DRIVERS-$(CONFIG_SOUND) += drivers/sound/sounddrivers.o -DRIVERS-$(CONFIG_PCI) += drivers/pci/pci.a +DRIVERS-$(CONFIG_PCI) += drivers/pci/driver.o DRIVERS-$(CONFIG_MTD) += drivers/mtd/mtdlink.o DRIVERS-$(CONFIG_PCMCIA) += drivers/pcmcia/pcmcia.o DRIVERS-$(CONFIG_PCMCIA_NETCARD) += drivers/net/pcmcia/pcmcia_net.o DRIVERS-$(CONFIG_PCMCIA_CHRDEV) += drivers/char/pcmcia/pcmcia_char.o DRIVERS-$(CONFIG_DIO) += drivers/dio/dio.a DRIVERS-$(CONFIG_SBUS) += drivers/sbus/sbus_all.o -DRIVERS-$(CONFIG_ZORRO) += drivers/zorro/zorro.a +DRIVERS-$(CONFIG_ZORRO) += drivers/zorro/driver.o DRIVERS-$(CONFIG_FC4) += drivers/fc4/fc4.a DRIVERS-$(CONFIG_ALL_PPC) += drivers/macintosh/macintosh.o DRIVERS-$(CONFIG_MAC) += drivers/macintosh/macintosh.o @@ -175,7 +175,7 @@ DRIVERS-$(CONFIG_IRDA) += drivers/net/irda/irda.o DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.o -DRIVERS-$(CONFIG_ACPI_INTERPRETER) += drivers/acpi/acpi.o +DRIVERS-$(CONFIG_ACPI) += drivers/acpi/acpi.o DRIVERS-$(CONFIG_MD) += drivers/md/mddev.o DRIVERS += $(DRIVERS-y) diff -u --recursive --new-file v2.4.0-test12/linux/Rules.make linux/Rules.make --- v2.4.0-test12/linux/Rules.make Sun Oct 8 10:50:04 2000 +++ linux/Rules.make Fri Dec 29 14:07:19 2000 @@ -19,18 +19,17 @@ unexport ALL_SUB_DIRS unexport MOD_SUB_DIRS unexport O_TARGET -unexport O_OBJS -unexport L_OBJS -unexport M_OBJS -# intermediate objects that form part of a module -unexport MI_OBJS unexport ALL_MOBJS -# objects that export symbol tables -unexport OX_OBJS -unexport LX_OBJS -unexport MX_OBJS -unexport MIX_OBJS -unexport SYMTAB_OBJS + +unexport obj-y +unexport obj-m +unexport obj-n +unexport obj- +unexport export-objs +unexport subdir-y +unexport subdir-m +unexport subdir-n +unexport subdir- # # Get things started. @@ -38,6 +37,12 @@ first_rule: sub_dirs $(MAKE) all_targets +both-m := $(filter $(mod-subdirs), $(subdir-y)) +SUB_DIRS := $(subdir-y) +MOD_SUB_DIRS := $(sort $(subdir-m) $(both-m)) +ALL_SUB_DIRS := $(sort $(subdir-y) $(subdir-m) $(subdir-n) $(subdir-)) + + # # Common rules # @@ -85,16 +90,15 @@ # Rule to compile a set of .o files into one .o file # ifdef O_TARGET -ALL_O = $(OX_OBJS) $(O_OBJS) -$(O_TARGET): $(ALL_O) +$(O_TARGET): $(obj-y) rm -f $@ - ifneq "$(strip $(ALL_O))" "" - $(LD) $(EXTRA_LDFLAGS) -r -o $@ $(filter $(ALL_O), $^) + ifneq "$(strip $(obj-y))" "" + $(LD) $(EXTRA_LDFLAGS) -r -o $@ $(filter $(obj-y), $^) else - $(AR) rcs $@ $(filter $(ALL_O), $^) + $(AR) rcs $@ endif @ ( \ - echo 'ifeq ($(strip $(subst $(comma),:,$(EXTRA_LDFLAGS) $(ALL_O))),$$(strip $$(subst $$(comma),:,$$(EXTRA_LDFLAGS) $$(ALL_O))))' ; \ + echo 'ifeq ($(strip $(subst $(comma),:,$(EXTRA_LDFLAGS) $(obj-y))),$$(strip $$(subst $$(comma),:,$$(EXTRA_LDFLAGS) $$(obj-y))))' ; \ echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \ echo 'endif' \ ) > $(dir $@)/.$(notdir $@).flags @@ -104,16 +108,17 @@ # Rule to compile a set of .o files into one .a file # ifdef L_TARGET -$(L_TARGET): $(LX_OBJS) $(L_OBJS) +$(L_TARGET): $(obj-y) rm -f $@ - $(AR) $(EXTRA_ARFLAGS) rcs $@ $(LX_OBJS) $(L_OBJS) + $(AR) $(EXTRA_ARFLAGS) rcs $@ $(obj-y) @ ( \ - echo 'ifeq ($(strip $(subst $(comma),:,$(EXTRA_ARFLAGS) $(LX_OBJS) $(L_OBJS))),$$(strip $$(subst $$(comma),:,$$(EXTRA_ARFLAGS) $$(LX_OBJS) $$(L_OBJS))))' ; \ + echo 'ifeq ($(strip $(subst $(comma),:,$(EXTRA_ARFLAGS) $(obj-y))),$$(strip $$(subst $$(comma),:,$$(EXTRA_ARFLAGS) $$(obj-y))))' ; \ echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \ echo 'endif' \ ) > $(dir $@)/.$(notdir $@).flags endif + # # This make dependencies quickly # @@ -132,17 +137,18 @@ # # A rule to make subdirectories # -sub_dirs: dummy $(patsubst %,_subdir_%,$(SUB_DIRS)) +subdir-list = $(sort $(patsubst %,_subdir_%,$(SUB_DIRS))) +sub_dirs: dummy $(subdir-list) ifdef SUB_DIRS -$(patsubst %,_subdir_%,$(SUB_DIRS)) : dummy +$(subdir-list) : dummy $(MAKE) -C $(patsubst _subdir_%,%,$@) endif # # A rule to make modules # -ALL_MOBJS = $(MX_OBJS) $(M_OBJS) +ALL_MOBJS = $(filter-out $(obj-y), $(obj-m)) ifneq "$(strip $(ALL_MOBJS))" "" PDWN=$(shell $(CONFIG_SHELL) $(TOPDIR)/scripts/pathdown.sh) endif @@ -160,7 +166,7 @@ endif .PHONY: modules -modules: $(ALL_MOBJS) $(MIX_OBJS) $(MI_OBJS) dummy \ +modules: $(ALL_MOBJS) dummy \ $(patsubst %,_modsubdir_%,$(MOD_DIRS)) .PHONY: _modinst__ @@ -187,16 +193,17 @@ # # This sets version suffixes on exported symbols -# Uses SYMTAB_OBJS # Separate the object into "normal" objects and "exporting" objects # Exporting objects are: all objects that define symbol tables # ifdef CONFIG_MODULES -SYMTAB_OBJS = $(LX_OBJS) $(OX_OBJS) $(MX_OBJS) $(MIX_OBJS) +multi-used := $(filter $(list-multi), $(obj-y) $(obj-m)) +multi-objs := $(foreach m, $(multi-used), $($(basename $(m))-objs)) +active-objs := $(sort $(multi-objs) $(obj-y) $(obj-m)) ifdef CONFIG_MODVERSIONS -ifneq "$(strip $(SYMTAB_OBJS))" "" +ifneq "$(strip $(export-objs))" "" MODINCL = $(TOPDIR)/include/linux/modules @@ -223,15 +230,15 @@ else echo mv $@.tmp $@; mv -f $@.tmp $@; fi; \ fi; touch $(MODINCL)/$*.stamp -$(addprefix $(MODINCL)/,$(SYMTAB_OBJS:.o=.ver)): $(TOPDIR)/include/linux/autoconf.h +$(addprefix $(MODINCL)/,$(export-objs:.o=.ver)): $(TOPDIR)/include/linux/autoconf.h # updates .ver files but not modversions.h -fastdep: $(addprefix $(MODINCL)/,$(SYMTAB_OBJS:.o=.ver)) +fastdep: $(addprefix $(MODINCL)/,$(export-objs:.o=.ver)) # updates .ver files and modversions.h like before (is this needed?) dep: fastdep update-modverfile -endif # SYMTAB_OBJS +endif # export-objs # update modversions.h, but only if it would change update-modverfile: @@ -252,10 +259,7 @@ mv -f $(TOPDIR)/include/linux/modversions.h.tmp $(TOPDIR)/include/linux/modversions.h; \ fi -$(M_OBJS): $(TOPDIR)/include/linux/modversions.h -ifdef MAKING_MODULES -$(O_OBJS) $(L_OBJS): $(TOPDIR)/include/linux/modversions.h -endif +$(active-objs): $(TOPDIR)/include/linux/modversions.h else @@ -264,8 +268,8 @@ endif # CONFIG_MODVERSIONS -ifneq "$(strip $(SYMTAB_OBJS))" "" -$(SYMTAB_OBJS): $(SYMTAB_OBJS:.o=.c) $(TOPDIR)/include/linux/modversions.h +ifneq "$(strip $(export-objs))" "" +$(export-objs): $(export-objs:.o=.c) $(TOPDIR)/include/linux/modversions.h $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -DEXPORT_SYMTAB -c $(@:.o=.c) @ ( \ echo 'ifeq ($(strip $(subst $(comma),:,$(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -DEXPORT_SYMTAB)),$$(strip $$(subst $$(comma),:,$$(CFLAGS) $$(EXTRA_CFLAGS) $$(CFLAGS_$@) -DEXPORT_SYMTAB)))' ; \ @@ -305,10 +309,7 @@ FILES_FLAGS_CHANGED := $(strip \ $(filter-out $(FILES_FLAGS_UP_TO_DATE), \ - $(O_TARGET) $(O_OBJS) $(OX_OBJS) \ - $(L_TARGET) $(L_OBJS) $(LX_OBJS) \ - $(M_OBJS) $(MX_OBJS) \ - $(MI_OBJS) $(MIX_OBJS) \ + $(O_TARGET) $(L_TARGET) $(active-objs) \ )) # A kludge: .S files don't get flag dependencies (yet), diff -u --recursive --new-file v2.4.0-test12/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v2.4.0-test12/linux/arch/alpha/config.in Mon Dec 11 17:59:43 2000 +++ linux/arch/alpha/config.in Fri Dec 29 14:07:19 2000 @@ -3,6 +3,7 @@ # see Documentation/kbuild/config-language.txt. # +define_bool CONFIG_ALPHA y define_bool CONFIG_UID16 n mainmenu_name "Kernel configuration of Linux for Alpha machines" diff -u --recursive --new-file v2.4.0-test12/linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile --- v2.4.0-test12/linux/arch/alpha/kernel/Makefile Mon Jun 19 17:59:32 2000 +++ linux/arch/alpha/kernel/Makefile Fri Dec 29 14:07:19 2000 @@ -13,29 +13,31 @@ $(CC) $(AFLAGS) -c -o $*.o $< O_TARGET := kernel.o -O_OBJS := entry.o traps.o process.o osf_sys.o irq.o irq_alpha.o \ - signal.o setup.o ptrace.o time.o semaphore.o -OX_OBJS := alpha_ksyms.o -L_TARGET := rest.a -L_OBJS := irq_i8259.o irq_srm.o irq_pyxis.o \ - es1888.o smc37c669.o smc37c93x.o ns87312.o +export-objs := alpha_ksyms.o -ifdef CONFIG_SMP -O_OBJS += smp.o irq_smp.o -endif +obj-y := entry.o traps.o process.o osf_sys.o irq.o irq_alpha.o \ + signal.o setup.o ptrace.o time.o semaphore.o alpha_ksyms.o -ifdef CONFIG_PCI -O_OBJS += pci.o pci_iommu.o -endif +# +# FIXME! +# These should be made conditional on the stuff that needs them! +# +obj-y += irq_i8259.o irq_srm.o irq_pyxis.o \ + es1888.o smc37c669.o smc37c93x.o ns87312.o ifdef CONFIG_VGA_HOSE -L_OBJS += console.o +obj-y += console.o endif + +obj-$(CONFIG_SMP) += smp.o irq_smp.o + +obj-$(CONFIG_PCI) += pci.o pci_iommu.o + ifdef CONFIG_ALPHA_GENERIC -O_OBJS += core_apecs.o core_cia.o core_irongate.o core_lca.o core_mcpcia.o \ +obj-y += core_apecs.o core_cia.o core_irongate.o core_lca.o core_mcpcia.o \ core_polaris.o core_t2.o core_tsunami.o core_titan.o \ sys_alcor.o sys_cabriolet.o sys_dp264.o sys_eb64p.o sys_eiger.o \ sys_jensen.o sys_miata.o sys_mikasa.o sys_nautilus.o sys_titan.o \ @@ -46,99 +48,53 @@ else # Core logic support -ifdef CONFIG_ALPHA_APECS -O_OBJS += core_apecs.o -endif -ifdef CONFIG_ALPHA_CIA -O_OBJS += core_cia.o -endif -ifdef CONFIG_ALPHA_IRONGATE -O_OBJS += core_irongate.o -endif -ifdef CONFIG_ALPHA_LCA -O_OBJS += core_lca.o -endif -ifdef CONFIG_ALPHA_MCPCIA -O_OBJS += core_mcpcia.o -endif -ifdef CONFIG_ALPHA_T2 -O_OBJS += core_t2.o -endif -ifdef CONFIG_ALPHA_TSUNAMI -O_OBJS += core_tsunami.o -endif -ifdef CONFIG_ALPHA_TITAN -O_OBJS += core_titan.o -endif -ifdef CONFIG_ALPHA_POLARIS -O_OBJS += core_polaris.o -endif -ifdef CONFIG_ALPHA_WILDFIRE -O_OBJS += core_wildfire.o -endif +obj-$(CONFIG_ALPHA_APECS) += core_apecs.o +obj-$(CONFIG_ALPHA_CIA) += core_cia.o + +obj-$(CONFIG_ALPHA_IRONGATE) += core_irongate.o +obj-$(CONFIG_ALPHA_LCA) += core_lca.o +obj-$(CONFIG_ALPHA_MCPCIA) += core_mcpcia.o +obj-$(CONFIG_ALPHA_T2) += core_t2.o +obj-$(CONFIG_ALPHA_TSUNAMI) += core_tsunami.o +obj-$(CONFIG_ALPHA_TITAN) += core_titan.o +obj-$(CONFIG_ALPHA_POLARIS) += core_polaris.o +obj-$(CONFIG_ALPHA_WILDFIRE) += core_wildfire.o # Board support ifneq ($(CONFIG_ALPHA_ALCOR)$(CONFIG_ALPHA_XLT),) -O_OBJS += sys_alcor.o +obj-y += sys_alcor.o endif ifneq ($(CONFIG_ALPHA_CABRIOLET)$(CONFIG_ALPHA_EB164)$(CONFIG_ALPHA_EB66P)$(CONFIG_ALPHA_LX164)$(CONFIG_ALPHA_PC164),) -O_OBJS += sys_cabriolet.o -endif -ifdef CONFIG_ALPHA_DP264 -O_OBJS += sys_dp264.o -endif -ifdef CONFIG_ALPHA_TITAN -O_OBJS += sys_titan.o +obj-y += sys_cabriolet.o endif + +obj-$(CONFIG_ALPHA_DP264) += sys_dp264.o +obj-$(CONFIG_ALPHA_TITAN) += sys_titan.o + ifneq ($(CONFIG_ALPHA_EB64P)$(CONFIG_ALPHA_EB66),) -O_OBJS += sys_eb64p.o -endif -ifdef CONFIG_ALPHA_EIGER -O_OBJS += sys_eiger.o -endif -ifdef CONFIG_ALPHA_JENSEN -O_OBJS += sys_jensen.o -endif -ifdef CONFIG_ALPHA_MIATA -O_OBJS += sys_miata.o -endif -ifdef CONFIG_ALPHA_MIKASA -O_OBJS += sys_mikasa.o -endif -ifdef CONFIG_ALPHA_NAUTILUS -O_OBJS += sys_nautilus.o -endif -ifdef CONFIG_ALPHA_NORITAKE -O_OBJS += sys_noritake.o -endif -ifdef CONFIG_ALPHA_RAWHIDE -O_OBJS += sys_rawhide.o -endif -ifdef CONFIG_ALPHA_RUFFIAN -O_OBJS += sys_ruffian.o -endif -ifdef CONFIG_ALPHA_RX164 -O_OBJS += sys_rx164.o -endif -ifdef CONFIG_ALPHA_SABLE -O_OBJS += sys_sable.o +obj-y += sys_eb64p.o endif + +obj-$(CONFIG_ALPHA_EIGER) += sys_eiger.o +obj-$(CONFIG_ALPHA_JENSEN) += sys_jensen.o +obj-$(CONFIG_ALPHA_MIATA) += sys_miata.o +obj-$(CONFIG_ALPHA_MIKASA) += sys_mikasa.o +obj-$(CONFIG_ALPHA_NAUTILUS) += sys_nautilus.o +obj-$(CONFIG_ALPHA_NORITAKE) += sys_noritake.o +obj-$(CONFIG_ALPHA_RAWHIDE) += sys_rawhide.o +obj-$(CONFIG_ALPHA_RUFFIAN) += sys_ruffian.o +obj-$(CONFIG_ALPHA_RX164) += sys_rx164.o +obj-$(CONFIG_ALPHA_SABLE) += sys_sable.o + ifneq ($(CONFIG_ALPHA_BOOK1)$(CONFIG_ALPHA_AVANTI)$(CONFIG_ALPHA_NONAME)$(CONFIG_ALPHA_P2K)$(CONFIG_ALPHA_XL),) -O_OBJS += sys_sio.o -endif -ifdef CONFIG_ALPHA_SX164 -O_OBJS += sys_sx164.o -endif -ifdef CONFIG_ALPHA_TAKARA -O_OBJS += sys_takara.o -endif -ifdef CONFIG_ALPHA_WILDFIRE -O_OBJS += sys_wildfire.o +obj-y += sys_sio.o endif -endif # GENERIC +obj-$(CONFIG_ALPHA_SX164) += sys_sx164.o +obj-$(CONFIG_ALPHA_TAKARA) += sys_takara.o +obj-$(CONFIG_ALPHA_WILDFIRE) += sys_wildfire.o -O_OBJS += $(L_TARGET) +endif # GENERIC all: kernel.o head.o diff -u --recursive --new-file v2.4.0-test12/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c --- v2.4.0-test12/linux/arch/alpha/kernel/smp.c Sun Oct 8 10:50:04 2000 +++ linux/arch/alpha/kernel/smp.c Fri Dec 29 14:07:19 2000 @@ -106,8 +106,9 @@ smp_store_cpu_info(int cpuid) { cpu_data[cpuid].loops_per_sec = loops_per_sec; - cpu_data[cpuid].last_asn - = (cpuid << WIDTH_HARDWARE_ASN) + ASN_FIRST_VERSION; + cpu_data[cpuid].last_asn = ASN_FIRST_VERSION; + cpu_data[cpuid].need_new_asn = 0; + cpu_data[cpuid].asn_lock = 0; local_irq_count(cpuid) = 0; local_bh_count(cpuid) = 0; } @@ -898,12 +899,16 @@ tbia(); } +#define asn_locked() (cpu_data[smp_processor_id()].asn_lock) + static void ipi_flush_tlb_mm(void *x) { struct mm_struct *mm = (struct mm_struct *) x; - if (mm == current->active_mm) + if (mm == current->active_mm && !asn_locked()) flush_tlb_current(mm); + else + flush_tlb_other(mm); } void @@ -911,10 +916,18 @@ { if (mm == current->active_mm) { flush_tlb_current(mm); - if (atomic_read(&mm->mm_users) <= 1) + if (atomic_read(&mm->mm_users) <= 1) { + int i, cpu, this_cpu = smp_processor_id(); + for (i = 0; i < smp_num_cpus; i++) { + cpu = cpu_logical_map(i); + if (cpu == this_cpu) + continue; + if (mm->context[cpu]) + mm->context[cpu] = 0; + } return; - } else - flush_tlb_other(mm); + } + } if (smp_call_function(ipi_flush_tlb_mm, mm, 1, 1)) { printk(KERN_CRIT "flush_tlb_mm: timed out\n"); @@ -931,8 +944,12 @@ ipi_flush_tlb_page(void *x) { struct flush_tlb_page_struct *data = (struct flush_tlb_page_struct *)x; - if (data->mm == current->active_mm) - flush_tlb_current_page(data->mm, data->vma, data->addr); + struct mm_struct * mm = data->mm; + + if (mm == current->active_mm && !asn_locked()) + flush_tlb_current_page(mm, data->vma, data->addr); + else + flush_tlb_other(mm); } void @@ -943,10 +960,18 @@ if (mm == current->active_mm) { flush_tlb_current_page(mm, vma, addr); - if (atomic_read(&mm->mm_users) <= 1) + if (atomic_read(&mm->mm_users) <= 1) { + int i, cpu, this_cpu = smp_processor_id(); + for (i = 0; i < smp_num_cpus; i++) { + cpu = cpu_logical_map(i); + if (cpu == this_cpu) + continue; + if (mm->context[cpu]) + mm->context[cpu] = 0; + } return; - } else - flush_tlb_other(mm); + } + } data.vma = vma; data.mm = mm; @@ -968,8 +993,10 @@ ipi_flush_icache_page(void *x) { struct mm_struct *mm = (struct mm_struct *) x; - if (mm == current->active_mm) + if (mm == current->active_mm && !asn_locked()) __load_new_mm_context(mm); + else + flush_tlb_other(mm); } void @@ -980,11 +1007,19 @@ if ((vma->vm_flags & VM_EXEC) == 0) return; - mm->context = 0; if (mm == current->active_mm) { __load_new_mm_context(mm); - if (atomic_read(&mm->mm_users) <= 1) + if (atomic_read(&mm->mm_users) <= 1) { + int i, cpu, this_cpu = smp_processor_id(); + for (i = 0; i < smp_num_cpus; i++) { + cpu = cpu_logical_map(i); + if (cpu == this_cpu) + continue; + if (mm->context[cpu]) + mm->context[cpu] = 0; + } return; + } } if (smp_call_function(ipi_flush_icache_page, mm, 1, 1)) { diff -u --recursive --new-file v2.4.0-test12/linux/arch/alpha/lib/Makefile linux/arch/alpha/lib/Makefile --- v2.4.0-test12/linux/arch/alpha/lib/Makefile Mon Dec 11 17:59:43 2000 +++ linux/arch/alpha/lib/Makefile Sat Dec 30 11:13:36 2000 @@ -35,7 +35,7 @@ $(ev6)stxcpy.o \ $(ev6)stxncpy.o \ $(ev67)strchr.o \ - strrchr.o \ + $(ev67)strrchr.o \ $(ev6)memchr.o \ $(ev6)copy_user.o \ $(ev6)clear_user.o \ diff -u --recursive --new-file v2.4.0-test12/linux/arch/alpha/lib/ev6-memcpy.S linux/arch/alpha/lib/ev6-memcpy.S --- v2.4.0-test12/linux/arch/alpha/lib/ev6-memcpy.S Mon Dec 11 17:59:43 2000 +++ linux/arch/alpha/lib/ev6-memcpy.S Sat Dec 30 11:13:36 2000 @@ -76,7 +76,7 @@ $do_unroll: addq $16, 64, $7 # E : Initial (+1 trip) wh64 address - cmple $18, 63, $1 # E : Can we go through the unrolled loop? + cmple $18, 127, $1 # E : Can we go through the unrolled loop? bne $1, $tail_quads # U : Nope nop # E : diff -u --recursive --new-file v2.4.0-test12/linux/arch/alpha/lib/ev67-strrchr.S linux/arch/alpha/lib/ev67-strrchr.S --- v2.4.0-test12/linux/arch/alpha/lib/ev67-strrchr.S Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/lib/ev67-strrchr.S Sat Dec 30 11:13:36 2000 @@ -0,0 +1,109 @@ +/* + * arch/alpha/lib/ev67-strrchr.S + * 21264 version by Rick Gorton + * + * Finds length of a 0-terminated string. Optimized for the + * Alpha architecture: + * + * - memory accessed as aligned quadwords only + * - uses bcmpge to compare 8 bytes in parallel + * + * Much of the information about 21264 scheduling/coding comes from: + * Compiler Writer's Guide for the Alpha 21264 + * abbreviated as 'CWG' in other comments here + * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html + * Scheduling notation: + * E - either cluster + * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 + * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 + */ + + +#include + + .set noreorder + .set noat + + .align 4 + .ent strrchr + .globl strrchr +strrchr: + .frame sp, 0, ra + .prologue 0 + + and a1, 0xff, t2 # E : 00000000000000ch + insbl a1, 1, t4 # U : 000000000000ch00 + insbl a1, 2, t5 # U : 0000000000ch0000 + ldq_u t0, 0(a0) # L : load first quadword Latency=3 + + mov zero, t6 # E : t6 is last match aligned addr + or t2, t4, a1 # E : 000000000000chch + sll t5, 8, t3 # U : 00000000ch000000 + mov zero, t8 # E : t8 is last match byte compare mask + + andnot a0, 7, v0 # E : align source addr + or t5, t3, t3 # E : 00000000chch0000 + sll a1, 32, t2 # U : 0000chch00000000 + sll a1, 48, t4 # U : chch000000000000 + + or t4, a1, a1 # E : chch00000000chch + or t2, t3, t2 # E : 0000chchchch0000 + or a1, t2, a1 # E : chchchchchchchch + lda t5, -1 # E : build garbage mask + + cmpbge zero, t0, t1 # E : bits set iff byte == zero + mskqh t5, a0, t4 # E : Complete garbage mask + xor t0, a1, t2 # E : make bytes == c zero + cmpbge zero, t4, t4 # E : bits set iff byte is garbage + + cmpbge zero, t2, t3 # E : bits set iff byte == c + andnot t1, t4, t1 # E : clear garbage from null test + andnot t3, t4, t3 # E : clear garbage from char test + bne t1, $eos # U : did we already hit the terminator? + + /* Character search main loop */ +$loop: + ldq t0, 8(v0) # L : load next quadword + cmovne t3, v0, t6 # E : save previous comparisons match + nop # : Latency=2, extra map slot (keep nop with cmov) + nop + + cmovne t3, t3, t8 # E : Latency=2, extra map slot + nop # : keep with cmovne + addq v0, 8, v0 # E : + xor t0, a1, t2 # E : + + cmpbge zero, t0, t1 # E : bits set iff byte == zero + cmpbge zero, t2, t3 # E : bits set iff byte == c + beq t1, $loop # U : if we havnt seen a null, loop + nop + + /* Mask out character matches after terminator */ +$eos: + negq t1, t4 # E : isolate first null byte match + and t1, t4, t4 # E : + subq t4, 1, t5 # E : build a mask of the bytes upto... + or t4, t5, t4 # E : ... and including the null + + and t3, t4, t3 # E : mask out char matches after null + cmovne t3, t3, t8 # E : save it, if match found Latency=2, extra map slot + nop # : Keep with cmovne + nop + + cmovne t3, v0, t6 # E : + nop # : Keep with cmovne + /* Locate the address of the last matched character */ + ctlz t8, t2 # U0 : Latency=3 (0x40 for t8=0) + nop + + cmoveq t8, 0x3f, t2 # E : Compensate for case when no match is seen + nop # E : hide the cmov latency (2) behind ctlz latency + lda t5, 0x3f($31) # E : + subq t5, t2, t5 # E : Normalize leading zero count + + addq t6, t5, v0 # E : and add to quadword address + ret # L0 : Latency=3 + nop + nop + + .end strrchr diff -u --recursive --new-file v2.4.0-test12/linux/arch/alpha/lib/memmove.S linux/arch/alpha/lib/memmove.S --- v2.4.0-test12/linux/arch/alpha/lib/memmove.S Mon Dec 11 17:59:43 2000 +++ linux/arch/alpha/lib/memmove.S Sat Dec 30 11:13:36 2000 @@ -26,12 +26,16 @@ bne $1,memcpy and $2,7,$2 /* Test for src/dest co-alignment. */ - bne $2,$misaligned + and $16,7,$1 + cmpule $16,$17,$3 + bne $3,$memmove_up /* dest < src */ and $4,7,$1 - beq $1,$skip_aligned_byte_loop_head + bne $2,$misaligned_dn + unop + beq $1,$skip_aligned_byte_loop_head_dn -$aligned_byte_loop_head: +$aligned_byte_loop_head_dn: lda $4,-1($4) lda $5,-1($5) unop @@ -48,13 +52,13 @@ and $4,7,$6 stq_u $1,0($4) - bne $6,$aligned_byte_loop_head + bne $6,$aligned_byte_loop_head_dn -$skip_aligned_byte_loop_head: +$skip_aligned_byte_loop_head_dn: lda $18,-8($18) - blt $18,$skip_aligned_word_loop + blt $18,$skip_aligned_word_loop_dn -$aligned_word_loop: +$aligned_word_loop_dn: ldq $1,-8($5) nop lda $5,-8($5) @@ -63,22 +67,22 @@ stq $1,-8($4) nop lda $4,-8($4) - bge $18,$aligned_word_loop + bge $18,$aligned_word_loop_dn -$skip_aligned_word_loop: +$skip_aligned_word_loop_dn: lda $18,8($18) - bgt $18,$byte_loop_tail + bgt $18,$byte_loop_tail_dn unop ret $31,($26),1 .align 4 -$misaligned: +$misaligned_dn: nop fnop unop beq $18,$egress -$byte_loop_tail: +$byte_loop_tail_dn: ldq_u $3,-1($5) ldq_u $2,-1($4) lda $5,-1($5) @@ -91,8 +95,77 @@ bis $1,$2,$1 stq_u $1,0($4) + bgt $18,$byte_loop_tail_dn + br $egress + +$memmove_up: + mov $16,$4 + mov $17,$5 + bne $2,$misaligned_up + beq $1,$skip_aligned_byte_loop_head_up + +$aligned_byte_loop_head_up: + unop + ble $18,$egress + ldq_u $3,0($5) + ldq_u $2,0($4) + + lda $18,-1($18) + extbl $3,$5,$1 + insbl $1,$4,$1 + mskbl $2,$4,$2 + + bis $1,$2,$1 + lda $5,1($5) + stq_u $1,0($4) + lda $4,1($4) + + and $4,7,$6 + bne $6,$aligned_byte_loop_head_up + +$skip_aligned_byte_loop_head_up: + lda $18,-8($18) + blt $18,$skip_aligned_word_loop_up + +$aligned_word_loop_up: + ldq $1,0($5) + nop + lda $5,8($5) + lda $18,-8($18) + + stq $1,0($4) + nop + lda $4,8($4) + bge $18,$aligned_word_loop_up + +$skip_aligned_word_loop_up: + lda $18,8($18) + bgt $18,$byte_loop_tail_up + unop + ret $31,($26),1 + + .align 4 +$misaligned_up: + nop + fnop + unop + beq $18,$egress + +$byte_loop_tail_up: + ldq_u $3,0($5) + ldq_u $2,0($4) + lda $18,-1($18) + extbl $3,$5,$1 + + insbl $1,$4,$1 + mskbl $2,$4,$2 + bis $1,$2,$1 + stq_u $1,0($4) + + lda $5,1($5) + lda $4,1($4) nop - bgt $18,$byte_loop_tail + bgt $18,$byte_loop_tail_up $egress: ret $31,($26),1 diff -u --recursive --new-file v2.4.0-test12/linux/arch/alpha/math-emu/Makefile linux/arch/alpha/math-emu/Makefile --- v2.4.0-test12/linux/arch/alpha/math-emu/Makefile Sun Oct 8 10:50:05 2000 +++ linux/arch/alpha/math-emu/Makefile Sat Dec 30 11:13:36 2000 @@ -1,18 +1,22 @@ # # Makefile for the FPU instruction emulation. # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definition is now in the main makefile... -O_TARGET := math-emu.o -O_OBJS := math.o qrnnd.o CFLAGS += -I. -I$(TOPDIR)/include/math-emu -w -ifeq ($(CONFIG_MATHEMU),m) -M_OBJS := $(O_TARGET) +ifeq ($(CONFIG_MATHEMU),y) + +O_TARGET := math-emu.o +obj-y := math.o qrnnd.o + +else + +list-multi := math-emu.o +math-emu-objs := math.o qrnnd.o +obj-m := math-emu.o +math-emu.o: $(math-emu-objs) + $(LD) -r -o $@ $(math-emu-objs) + endif include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test12/linux/arch/alpha/mm/fault.c linux/arch/alpha/mm/fault.c --- v2.4.0-test12/linux/arch/alpha/mm/fault.c Tue Oct 31 12:42:25 2000 +++ linux/arch/alpha/mm/fault.c Fri Dec 29 14:07:19 2000 @@ -45,7 +45,7 @@ unsigned long mmc; mmc = __get_new_mm_context(next_mm, smp_processor_id()); - next_mm->context = mmc; + next_mm->context[smp_processor_id()] = mmc; current->thread.asn = mmc & HARDWARE_ASN_MASK; current->thread.ptbr = ((unsigned long) next_mm->pgd - IDENT_ADDR) >> PAGE_SHIFT; diff -u --recursive --new-file v2.4.0-test12/linux/arch/i386/Makefile linux/arch/i386/Makefile --- v2.4.0-test12/linux/arch/i386/Makefile Sun Nov 19 18:44:02 2000 +++ linux/arch/i386/Makefile Fri Dec 29 14:07:19 2000 @@ -85,12 +85,13 @@ HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o SUBDIRS += arch/i386/kernel arch/i386/mm arch/i386/lib + CORE_FILES := arch/i386/kernel/kernel.o arch/i386/mm/mm.o $(CORE_FILES) LIBS := $(TOPDIR)/arch/i386/lib/lib.a $(LIBS) $(TOPDIR)/arch/i386/lib/lib.a ifdef CONFIG_MATH_EMULATION SUBDIRS += arch/i386/math-emu -DRIVERS += arch/i386/math-emu/math.a +DRIVERS += arch/i386/math-emu/math.o endif arch/i386/kernel: dummy diff -u --recursive --new-file v2.4.0-test12/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S --- v2.4.0-test12/linux/arch/i386/boot/setup.S Mon Dec 11 17:59:43 2000 +++ linux/arch/i386/boot/setup.S Fri Dec 29 14:07:57 2000 @@ -289,10 +289,11 @@ # a whole bunch of different types, and allows memory holes and # everything. We scan through this memory map and build a list # of the first 32 memory areas, which we return at [E820MAP]. -# +# This is documented at http://www.teleport.com/~acpi/acpihtml/topic245.htm + +#define SMAP 0x534d4150 meme820: - movl $0x534d4150, %edx # ascii `SMAP' xorl %ebx, %ebx # continuation counter movw $E820MAP, %di # point into the whitelist # so we can have the bios @@ -300,13 +301,14 @@ jmpe820: movl $0x0000e820, %eax # e820, upper word zeroed + movl $SMAP, %edx # ascii 'SMAP' movl $20, %ecx # size of the e820rec pushw %ds # data record. popw %es int $0x15 # make the call jc bail820 # fall to e801 if it fails - cmpl $0x534d4150, %eax # check the return is `SMAP' + cmpl $SMAP, %eax # check the return is `SMAP' jne bail820 # fall to e801 if it fails # cmpl $1, 16(%di) # is this usable memory? diff -u --recursive --new-file v2.4.0-test12/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.4.0-test12/linux/arch/i386/config.in Mon Dec 11 17:59:43 2000 +++ linux/arch/i386/config.in Fri Dec 29 14:35:47 2000 @@ -44,6 +44,9 @@ # # Define implied options from the CPU selection here # + +unset CONFIG_X86_FXSR + if [ "$CONFIG_M386" = "y" ]; then define_bool CONFIG_X86_CMPXCHG n define_int CONFIG_X86_L1_CACHE_SHIFT 4 @@ -136,7 +139,6 @@ define_bool CONFIG_X86_ALIGNMENT_16 y define_bool CONFIG_X86_TSC y define_bool CONFIG_X86_USE_PPRO_CHECKSUM y - define_bool CONFIG_X86_USE_3DNOW y fi tristate 'Toshiba Laptop support' CONFIG_TOSHIBA @@ -162,15 +164,15 @@ bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR bool 'Symmetric multi-processing support' CONFIG_SMP if [ "$CONFIG_SMP" != "y" ]; then - bool 'APIC and IO-APIC support on uniprocessors' CONFIG_X86_UP_IOAPIC - if [ "$CONFIG_X86_UP_IOAPIC" = "y" ]; then - define_bool CONFIG_X86_IO_APIC y - define_bool CONFIG_X86_LOCAL_APIC y - fi + bool 'APIC and IO-APIC support on uniprocessors' CONFIG_X86_UP_IOAPIC + if [ "$CONFIG_X86_UP_IOAPIC" = "y" ]; then + define_bool CONFIG_X86_IO_APIC y + define_bool CONFIG_X86_LOCAL_APIC y + fi fi if [ "$CONFIG_SMP" = "y" -a "$CONFIG_X86_CMPXCHG" = "y" ]; then - define_bool CONFIG_HAVE_DEC_LOCK y + define_bool CONFIG_HAVE_DEC_LOCK y fi endmenu @@ -235,12 +237,8 @@ bool 'Power Management support' CONFIG_PM -dep_bool ' ACPI support' CONFIG_ACPI $CONFIG_PM -if [ "$CONFIG_ACPI" != "n" ]; then - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' ACPI interpreter (EXPERIMENTAL)' CONFIG_ACPI_INTERPRETER - bool ' Enter S1 for sleep (EXPERIMENTAL)' CONFIG_ACPI_S1_SLEEP - fi +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_bool ' ACPI support' CONFIG_ACPI $CONFIG_PM fi dep_tristate ' Advanced Power Management BIOS support' CONFIG_APM $CONFIG_PM @@ -278,10 +276,10 @@ tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE if [ "$CONFIG_IDE" != "n" ]; then - source drivers/ide/Config.in + source drivers/ide/Config.in else - define_bool CONFIG_BLK_DEV_IDE_MODES n - define_bool CONFIG_BLK_DEV_HD n + define_bool CONFIG_BLK_DEV_IDE_MODES n + define_bool CONFIG_BLK_DEV_HD n fi endmenu diff -u --recursive --new-file v2.4.0-test12/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.4.0-test12/linux/arch/i386/defconfig Mon Dec 11 17:59:43 2000 +++ linux/arch/i386/defconfig Sun Dec 31 09:17:18 2000 @@ -92,7 +92,6 @@ CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=y CONFIG_PM=y -CONFIG_ACPI=y # CONFIG_APM is not set # @@ -256,6 +255,7 @@ CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 # CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set # CONFIG_BLK_DEV_SR is not set # CONFIG_CHR_DEV_SG is not set @@ -592,8 +592,6 @@ # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set @@ -602,6 +600,7 @@ # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set # CONFIG_NLS is not set # diff -u --recursive --new-file v2.4.0-test12/linux/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile --- v2.4.0-test12/linux/arch/i386/kernel/Makefile Sun Oct 8 10:50:06 2000 +++ linux/arch/i386/kernel/Makefile Fri Dec 29 14:35:47 2000 @@ -18,7 +18,7 @@ obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \ - pci-dma.o i386_ksyms.o i387.o bluesmoke.o + pci-dma.o i386_ksyms.o i387.o bluesmoke.o dmi_scan.o ifdef CONFIG_PCI @@ -40,15 +40,5 @@ obj-$(CONFIG_X86_LOCAL_APIC) += apic.o obj-$(CONFIG_X86_IO_APIC) += io_apic.o mpparse.o obj-$(CONFIG_X86_VISWS_APIC) += visws_apic.o - -# if the interpreter is used, it overrides acpi.c -ifneq ($(CONFIG_ACPI_INTERPRETER),y) -obj-$(CONFIG_ACPI) += acpi.o -endif - -O_OBJS := $(filter-out $(export-objs), $(obj-y)) -OX_OBJS := $(filter $(export-objs), $(obj-y)) -M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) -MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test12/linux/arch/i386/kernel/acpi.c linux/arch/i386/kernel/acpi.c --- v2.4.0-test12/linux/arch/i386/kernel/acpi.c Sun Nov 19 18:44:02 2000 +++ linux/arch/i386/kernel/acpi.c Wed Dec 31 16:00:00 1969 @@ -1,1935 +0,0 @@ -/* - * acpi.c - Linux ACPI driver - * - * Copyright (C) 1999-2000 Andrew Henroid - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * See http://www.geocities.com/SiliconValley/Hardware/3165/ - * for the user-level ACPI stuff - * - * Changes: - * Arnaldo Carvalho de Melo - 2000/08/31 - * - check copy*user return - * - get rid of check_region - * - get rid of verify_area - * Arnaldo Carvalho de Melo - 2000/09/28 - * - do proper release on failure in acpi_claim_ioports and acpi_init - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Yes, it's unfortunate that we are relying on get_cmos_time - * because it is slow (> 1 sec.) and i386 only. It might be better - * to use some of the code from drivers/char/rtc.c in the near future - */ -extern unsigned long get_cmos_time(void); - -static int acpi_do_ulong(ctl_table *ctl, - int write, - struct file *file, - void *buffer, - size_t *len); -static int acpi_do_table(ctl_table *ctl, - int write, - struct file *file, - void *buffer, - size_t *len); -static int acpi_do_event_reg(ctl_table *ctl, - int write, - struct file *file, - void *buffer, - size_t *len); -static int acpi_do_event(ctl_table *ctl, - int write, - struct file *file, - void *buffer, - size_t *len); -static int acpi_do_sleep(ctl_table *ctl, - int write, - struct file *file, - void *buffer, - size_t *len); -static void acpi_release(unsigned long start, unsigned long size); - -static struct ctl_table_header *acpi_sysctl = NULL; - -// current system sleep state (S0 - S4) -static acpi_sstate_t acpi_sleep_state = ACPI_S0; -// time sleep began -static unsigned long acpi_sleep_start = 0; - -static spinlock_t acpi_event_lock = SPIN_LOCK_UNLOCKED; -static volatile u32 acpi_pm1_status = 0; -static volatile u32 acpi_gpe_status = 0; -static volatile u32 acpi_gpe_level = 0; -static volatile acpi_sstate_t acpi_event_state = ACPI_S0; -static DECLARE_WAIT_QUEUE_HEAD(acpi_event_wait); - -/* Make it impossible to enter C2/C3 until after we've initialized */ -static unsigned long acpi_enter_lvl2_lat = ACPI_INFINITE_LAT; -static unsigned long acpi_enter_lvl3_lat = ACPI_INFINITE_LAT; -static unsigned long acpi_p_lvl2_lat = ACPI_INFINITE_LAT; -static unsigned long acpi_p_lvl3_lat = ACPI_INFINITE_LAT; - -/* Statistics.. */ -struct Cx_stat_struct { - unsigned long time; - unsigned long min; - unsigned long max; - unsigned long avg; -} Cx_stat[3]; - -static int acpi_do_stat(ctl_table *ctl, - int write, - struct file *file, - void *buffer, - size_t *len) -{ - int size; - char str[4*10]; - struct Cx_stat_struct *stat = (struct Cx_stat_struct *)ctl->data; - - if (write) { - stat->time = 0; - stat->min = 0; - stat->max = 0; - stat->avg = 0; - return 0; - } - - if (file->f_pos) { - *len = 0; - return 0; - } - size = sprintf(str, "%9lu %9lu %9lu %9lu", - stat->time, - stat->min, - stat->max, - stat->avg); - if (*len < size) { - *len = 0; - return 0; - } - return copy_to_user(buffer, str, size) ? -EFAULT : 0; -} - -static void cx_statistics(unsigned int x, unsigned long time) -{ - struct Cx_stat_struct *stat = Cx_stat + (x-1); - - stat->time += time; - if (time <= stat->min-1) - stat->min = time; - if (time > stat->max) - stat->max = time; - stat->avg = time + (stat->avg >> 1); -} - -static unsigned long acpi_p_blk = 0; - -static int acpi_p_lvl2_tested = 0; -static int acpi_p_lvl3_tested = 0; - -enum -{ - ACPI_ENABLED = 0x00000000, // use ACPI if present - ACPI_DISABLED = 0x00000001, // never use ACPI - ACPI_TABLES_ONLY = 0x00000002, // never use chipset-specific driver - ACPI_CHIPSET_ONLY = 0x00000004, // always use chipset-specific driver - ACPI_IGNORE_ERRATA = 0x00000008, // ignore any listed platform errata - ACPI_COPY_TABLES = 0x00000010, // copy ACPI tables before use - ACPI_TRUST_TABLES = 0x00000020, // use tables even after ioremap fails - ACPI_SCI_DISABLED = 0x00000040, // never enable ACPI (info. only) - ACPI_C2_DISABLED = 0x00000080, // never enter C2 - ACPI_C3_DISABLED = 0x00000100, // never enter C3 - ACPI_S1_DISABLED = 0x00000200, // never enter S1 - ACPI_S5_DISABLED = 0x00000400, // never enter S5 -}; - -struct acpi_option_info -{ - const char *name; - unsigned long value; -}; - -static struct acpi_option_info acpi_options[] = -{ - {"on", ACPI_ENABLED}, - {"off", ACPI_DISABLED}, - {"tables", ACPI_TABLES_ONLY}, - {"chipset", ACPI_CHIPSET_ONLY}, - {"no-errata", ACPI_IGNORE_ERRATA}, - {"copy-tables", ACPI_COPY_TABLES}, - {"trust-tables", ACPI_TRUST_TABLES}, - {"no-sci", ACPI_SCI_DISABLED}, - {"no-c2", ACPI_C2_DISABLED}, - {"no-c3", ACPI_C3_DISABLED}, - {"no-s1", ACPI_S1_DISABLED}, - {"no-s5", ACPI_S5_DISABLED}, - {NULL, 0}, -}; - -static unsigned long acpi_opts = ACPI_ENABLED; - -struct acpi_errata_info -{ - const char *signature; // table signature (eg. "RSDT") - const char *oem; // OEM name - const char *oem_table; // OEM table identifier (optional) - u32 oem_rev; // OEM table revision (optional) - unsigned long options; // errata options -}; - -/* - * We must identify systems that need ACPI_TRUST_TABLES solely from the - * RSDP ("RSD PTR "). All other options should be flagged from the - * RSDT ("RSDT") which can be better identified. - */ -struct acpi_errata_info acpi_errata[] = -{ - {"RSD PTR ", "AMI ", NULL, 0, ACPI_TRUST_TABLES | ACPI_COPY_TABLES}, - {NULL, NULL, 0, 0}, -}; - -// bits 8-15 are SLP_TYPa, bits 0-7 are SLP_TYPb -static unsigned long acpi_slp_typ[] = -{ - ACPI_SLP_TYP_DISABLED, /* S0 */ - ACPI_SLP_TYP_DISABLED, /* S1 */ - ACPI_SLP_TYP_DISABLED, /* S2 */ - ACPI_SLP_TYP_DISABLED, /* S3 */ - ACPI_SLP_TYP_DISABLED, /* S4 */ - ACPI_SLP_TYP_DISABLED /* S5 */ -}; - -struct acpi_table_info -{ - u32 expected_signature; - u32 expected_size; - - struct acpi_table *table; - size_t size; - int mapped; -}; - -static struct acpi_table_info acpi_facp - = {ACPI_FACP_SIG, sizeof(struct acpi_facp), NULL, 0, 0}; -static struct acpi_table_info acpi_dsdt = {ACPI_DSDT_SIG, 0, NULL, 0, 0}; -static struct acpi_table_info acpi_facs - = {ACPI_FACS_SIG, sizeof(struct acpi_facs), NULL, 0, 0}; -static rwlock_t acpi_do_table_lock = RW_LOCK_UNLOCKED; - -static struct ctl_table acpi_table[] = -{ - {ACPI_FACP, "facp", &acpi_facp, 0, 0644, NULL, &acpi_do_table}, - - {ACPI_DSDT, "dsdt", &acpi_dsdt, 0, 0644, NULL, &acpi_do_table}, - - {ACPI_FACS, "facs", &acpi_facs, 0, 0644, NULL, &acpi_do_table}, - - {ACPI_PM1_ENABLE, "pm1_enable", - NULL, 0, - 0600, NULL, &acpi_do_event_reg}, - - {ACPI_GPE_ENABLE, "gpe_enable", - NULL, 0, - 0600, NULL, &acpi_do_event_reg}, - - {ACPI_GPE_LEVEL, "gpe_level", - NULL, 0, - 0600, NULL, &acpi_do_event_reg}, - - {ACPI_EVENT, "event", NULL, 0, 0400, NULL, &acpi_do_event}, - - {ACPI_P_BLK, "p_blk", - &acpi_p_blk, sizeof(acpi_p_blk), - 0600, NULL, &acpi_do_ulong}, - - {ACPI_P_LVL2_LAT, "p_lvl2_lat", - &acpi_p_lvl2_lat, sizeof(acpi_p_lvl2_lat), - 0644, NULL, &acpi_do_ulong}, - - {ACPI_P_LVL3_LAT, "p_lvl3_lat", - &acpi_p_lvl3_lat, sizeof(acpi_p_lvl3_lat), - 0644, NULL, &acpi_do_ulong}, - - {ACPI_ENTER_LVL2_LAT, "enter_lvl2_lat", - &acpi_enter_lvl2_lat, sizeof(acpi_enter_lvl2_lat), - 0644, NULL, &acpi_do_ulong}, - - {ACPI_ENTER_LVL3_LAT, "enter_lvl3_lat", - &acpi_enter_lvl3_lat, sizeof(acpi_enter_lvl3_lat), - 0644, NULL, &acpi_do_ulong}, - - {ACPI_C1_TIME, "c1_time", - Cx_stat+0, sizeof(struct Cx_stat_struct), - 0644, NULL, &acpi_do_stat}, - - {ACPI_C2_TIME, "c2_time", - Cx_stat+1, sizeof(struct Cx_stat_struct), - 0644, NULL, &acpi_do_stat}, - - {ACPI_C3_TIME, "c3_time", - Cx_stat+2, sizeof(struct Cx_stat_struct), - 0644, NULL, &acpi_do_stat}, - - {ACPI_S0_SLP_TYP, "s0_slp_typ", - &acpi_slp_typ[ACPI_S0], sizeof(acpi_slp_typ[ACPI_S0]), - 0600, NULL, &acpi_do_ulong}, - - {ACPI_S1_SLP_TYP, "s1_slp_typ", - &acpi_slp_typ[ACPI_S1], sizeof(acpi_slp_typ[ACPI_S1]), - 0600, NULL, &acpi_do_ulong}, - - {ACPI_S5_SLP_TYP, "s5_slp_typ", - &acpi_slp_typ[ACPI_S5], sizeof(acpi_slp_typ[ACPI_S5]), - 0600, NULL, &acpi_do_ulong}, - - {ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &acpi_do_sleep}, - - {0} -}; - -static struct ctl_table acpi_dir_table[] = -{ - {CTL_ACPI, "acpi", NULL, 0, 0555, acpi_table}, - {0} -}; - -static u32 FASTCALL(acpi_read_pm1_control(struct acpi_facp *)); -static u32 FASTCALL(acpi_read_pm1_status(struct acpi_facp *)); -static u32 FASTCALL(acpi_read_pm1_enable(struct acpi_facp *)); -static u32 FASTCALL(acpi_read_gpe_status(struct acpi_facp *)); -static u32 FASTCALL(acpi_read_gpe_enable(struct acpi_facp *)); - -static void FASTCALL(acpi_write_pm1_control(struct acpi_facp *, u32)); -static void FASTCALL(acpi_write_pm1_status(struct acpi_facp *, u32)); -static void FASTCALL(acpi_write_pm1_enable(struct acpi_facp *, u32)); -static void FASTCALL(acpi_write_gpe_status(struct acpi_facp *, u32)); -static void FASTCALL(acpi_write_gpe_enable(struct acpi_facp *, u32)); - -/* - * Get the value of the PM1 control register (SCI_EN, ...) - */ -static u32 acpi_read_pm1_control(struct acpi_facp *facp) -{ - u32 value = 0; - if (facp->pm1a_cnt) - value = inw(facp->pm1a_cnt); - if (facp->pm1b_cnt) - value |= inw(facp->pm1b_cnt); - return value; -} - -/* - * Set the value of the PM1 control register (BM_RLD, ...) - */ -static void acpi_write_pm1_control(struct acpi_facp *facp, u32 value) -{ - if (facp->pm1a_cnt) - outw(value, facp->pm1a_cnt); - if (facp->pm1b_cnt) - outw(value, facp->pm1b_cnt); -} - -/* - * Get the value of the fixed event status register - */ -static u32 acpi_read_pm1_status(struct acpi_facp *facp) -{ - u32 value = 0; - if (facp->pm1a_evt) - value = inw(facp->pm1a_evt); - if (facp->pm1b_evt) - value |= inw(facp->pm1b_evt); - return value; -} - -/* - * Set the value of the fixed event status register (clear events) - */ -static void acpi_write_pm1_status(struct acpi_facp *facp, u32 value) -{ - if (facp->pm1a_evt) - outw(value, facp->pm1a_evt); - if (facp->pm1b_evt) - outw(value, facp->pm1b_evt); -} - -/* - * Get the value of the fixed event enable register - */ -static u32 acpi_read_pm1_enable(struct acpi_facp *facp) -{ - int offset = facp->pm1_evt_len >> 1; - u32 value = 0; - if (facp->pm1a_evt) - value = inw(facp->pm1a_evt + offset); - if (facp->pm1b_evt) - value |= inw(facp->pm1b_evt + offset); - return value; -} - -/* - * Set the value of the fixed event enable register (enable events) - */ -static void acpi_write_pm1_enable(struct acpi_facp *facp, u32 value) -{ - int offset = facp->pm1_evt_len >> 1; - if (facp->pm1a_evt) - outw(value, facp->pm1a_evt + offset); - if (facp->pm1b_evt) - outw(value, facp->pm1b_evt + offset); -} - -/* - * Get the value of the general-purpose event status register - */ -static u32 acpi_read_gpe_status(struct acpi_facp *facp) -{ - u32 value = 0; - int i, size; - - if (facp->gpe1) { - size = facp->gpe1_len >> 1; - for (i = size - 1; i >= 0; i--) - value = (value << 8) | inb(facp->gpe1 + i); - } - if (facp->gpe0) { - size = facp->gpe0_len >> 1; - for (i = size - 1; i >= 0; i--) - value = (value << 8) | inb(facp->gpe0 + i); - } - return value; -} - -/* - * Set the value of the general-purpose event status register (clear events) - */ -static void acpi_write_gpe_status(struct acpi_facp *facp, u32 value) -{ - int i, size; - - if (facp->gpe0) { - size = facp->gpe0_len >> 1; - for (i = 0; i < size; i++) { - outb(value & 0xff, facp->gpe0 + i); - value >>= 8; - } - } - if (facp->gpe1) { - size = facp->gpe1_len >> 1; - for (i = 0; i < size; i++) { - outb(value & 0xff, facp->gpe1 + i); - value >>= 8; - } - } -} - -/* - * Get the value of the general-purpose event enable register - */ -static u32 acpi_read_gpe_enable(struct acpi_facp *facp) -{ - u32 value = 0; - int i, size, offset; - - offset = facp->gpe0_len >> 1; - if (facp->gpe1) { - size = facp->gpe1_len >> 1; - for (i = size - 1; i >= 0; i--) { - value = (value << 8) | inb(facp->gpe1 + offset + i); - } - } - if (facp->gpe0) { - size = facp->gpe0_len >> 1; - for (i = size - 1; i >= 0; i--) - value = (value << 8) | inb(facp->gpe0 + offset + i); - } - return value; -} - -/* - * Set the value of the general-purpose event enable register (enable events) - */ -static void acpi_write_gpe_enable(struct acpi_facp *facp, u32 value) -{ - int i, offset; - - offset = facp->gpe0_len >> 1; - if (facp->gpe0) { - for (i = 0; i < offset; i++) { - outb(value & 0xff, facp->gpe0 + offset + i); - value >>= 8; - } - } - if (facp->gpe1) { - offset = facp->gpe1_len >> 1; - for (i = 0; i < offset; i++) { - outb(value & 0xff, facp->gpe1 + offset + i); - value >>= 8; - } - } -} - -/* - * Map an ACPI table into virtual memory - */ -static struct acpi_table *__init acpi_map_table(u32 addr) -{ - struct acpi_table *table = NULL; - if (addr) { - // map table header to determine size - table = (struct acpi_table *) - ioremap((unsigned long) addr, - sizeof(struct acpi_table)); - if (table) { - unsigned long table_size = table->length; - iounmap(table); - // remap entire table - table = (struct acpi_table *) - ioremap((unsigned long) addr, table_size); - } - - if (!table && addr < virt_to_phys(high_memory)) { - /* sometimes we see ACPI tables in low memory - * and not reserved by the memory map (E820) code, - * who is at fault for this? BIOS? - */ - printk(KERN_ERR - "ACPI: unreserved table memory @ 0x%p!\n", - (void*) addr); - - if (acpi_opts & ACPI_TRUST_TABLES) { - /* OK, trust that the table is there - * if it isn't you'll get an OOPS here - */ - static u32 sig; - table = (struct acpi_table *) - phys_to_virt(addr); - sig = table->signature; - } - } - } - return table; -} - -/* - * Unmap an ACPI table from virtual memory - */ -static void acpi_unmap_table(struct acpi_table *table) -{ - // iounmap ignores addresses within physical memory - if (table) - iounmap(table); -} - -/* - * Initialize an ACPI table - */ -static int acpi_init_table(struct acpi_table_info *info, - void *data, - int mapped) -{ - struct acpi_table *table = (struct acpi_table*) data; - - info->table = NULL; - info->size = 0; - info->mapped = 0; - - if (!table || table->signature != info->expected_signature) - return -EINVAL; - - if (mapped && (acpi_opts & ACPI_COPY_TABLES)) { - struct acpi_table *copy - = kmalloc(table->length, GFP_KERNEL); - if (!copy) - return -ENOMEM; - memcpy(copy, table, table->length); - table = copy; - mapped = 0; - } - - info->table = table; - info->size = (size_t) table->length; - info->mapped = mapped; - return 0; -} - -/* - * Destroy an ACPI table - */ -static void acpi_destroy_table(struct acpi_table_info *info) -{ - if (info->table) { - if (info->mapped) - acpi_unmap_table(info->table); - else - kfree(info->table); - info->table = NULL; - } -} - -/* - * Match ACPI table and set options based on platform errata, if any - */ -static int __init acpi_find_errata(struct acpi_table *table) -{ - struct acpi_errata_info *info; - int size; - - for (info = acpi_errata; info->signature && info->oem; info++) { - size = strlen(info->signature); - if (memcmp(&table->signature, info->signature, size)) - continue; - if (strcmp(info->signature, "RSD PTR ")) { - // ordinary ACPI table - size = strlen(info->oem); - if (memcmp(table->oem, info->oem, size)) - continue; - if (info->oem_table) { - size = strlen(info->oem_table); - if (memcmp(table->oem_table, - info->oem_table, - size)) - continue; - } - if (info->oem_rev && table->oem_rev != info->oem_rev) - continue; - } - else { - // special handling for RSDP - size = strlen(info->oem); - if (memcmp(((struct acpi_rsdp*) table)->oem, - info->oem, - size)) - continue; - } - - printk(KERN_INFO - "ACPI: found platform errata 0x%08lx\n", - info->options); - acpi_opts |= info->options; - return 0; - } - return -1; -} - -/* - * Locate and map ACPI tables - */ -static int __init acpi_find_tables(void) -{ - struct acpi_rsdp *rsdp; - struct acpi_table *rsdt; - u32 *rsdt_entry; - int rsdt_entry_count; - unsigned long i; - - // search BIOS memory for RSDP - for (i = ACPI_BIOS_ROM_BASE; i < ACPI_BIOS_ROM_END; i += 16) { - rsdp = (struct acpi_rsdp *) phys_to_virt(i); - if (rsdp->signature[0] == ACPI_RSDP1_SIG - && rsdp->signature[1] == ACPI_RSDP2_SIG) { - char oem[7]; - int j; - - // strip trailing space and print OEM identifier - memcpy(oem, rsdp->oem, 6); - oem[6] = '\0'; - for (j = 5; - j > 0 && (oem[j] == '\0' || oem[j] == ' '); - j--) { - oem[j] = '\0'; - } - printk(KERN_INFO "ACPI: \"%s\" found at 0x%p\n", - oem, (void *) i); - - break; - } - } - if (i >= ACPI_BIOS_ROM_END) - return -ENODEV; - - // find any errata based on the RSDP - if (!acpi_find_errata((struct acpi_table*) rsdp)) { - if (acpi_opts & ACPI_DISABLED) - return -EINVAL; - else if (acpi_opts & ACPI_CHIPSET_ONLY) - return -ENODEV; - } - - // fetch RSDT from RSDP - rsdt = acpi_map_table(rsdp->rsdt); - if (!rsdt) { - printk(KERN_ERR "ACPI: missing RSDT at 0x%p\n", - (void*) rsdp->rsdt); - return -EINVAL; - } - else if (rsdt->signature != ACPI_RSDT_SIG) { - printk(KERN_ERR "ACPI: bad RSDT at 0x%p (%08x)\n", - (void*) rsdp->rsdt, (unsigned) rsdt->signature); - acpi_unmap_table(rsdt); - return -EINVAL; - } - - // find any errata based on the RSDT - if (!acpi_find_errata(rsdt)) { - if (acpi_opts & ACPI_DISABLED) - return -EINVAL; - else if (acpi_opts & ACPI_CHIPSET_ONLY) - return -ENODEV; - } - - // search RSDT for FACP - acpi_facp.table = NULL; - rsdt_entry = (u32 *) (rsdt + 1); - rsdt_entry_count = (int) ((rsdt->length - sizeof(*rsdt)) >> 2); - while (rsdt_entry_count) { - struct acpi_table *dt = acpi_map_table(*rsdt_entry); - if (!acpi_init_table(&acpi_facp, dt, 1)) { - struct acpi_facp *facp - = (struct acpi_facp*) acpi_facp.table; - struct acpi_table *facs; - - // map DSDT if it exists - if ((dt = acpi_map_table(facp->dsdt))) { - if (acpi_init_table(&acpi_dsdt, dt, 1)) - acpi_unmap_table(dt); - } - - /* - * map FACS if it exists - */ - if ((facs = acpi_map_table(facp->facs))) { - if (acpi_init_table(&acpi_facs,facs,1)) - acpi_unmap_table(facs); - } - break; - } - else { - acpi_unmap_table(dt); - } - - rsdt_entry++; - rsdt_entry_count--; - } - - acpi_unmap_table(rsdt); - - if (!acpi_facp.table) { - printk(KERN_ERR "ACPI: missing FACP\n"); - return -EINVAL; - } - return 0; -} - -/* - * Unmap or destroy ACPI tables - */ -static void acpi_destroy_tables(void) -{ - acpi_destroy_table(&acpi_facs); - acpi_destroy_table(&acpi_dsdt); - acpi_destroy_table(&acpi_facp); -} - -/* - * Init PIIX4 device, create a fake FACP - */ -static int __init acpi_init_piix4(struct pci_dev *dev) -{ - struct acpi_facp *facp; - u32 base; - u16 cmd; - u8 pmregmisc; - - pci_read_config_word(dev, PCI_COMMAND, &cmd); - if (!(cmd & PCI_COMMAND_IO)) - return -ENODEV; - - pci_read_config_byte(dev, ACPI_PIIX4_PMREGMISC, &pmregmisc); - if (!(pmregmisc & ACPI_PIIX4_PMIOSE)) - return -ENODEV; - - base = pci_resource_start (dev, PCI_BRIDGE_RESOURCES); - if (!base) - return -ENODEV; - - printk(KERN_INFO "ACPI: found PIIX4 at 0x%04x\n", base); - - facp = kmalloc(sizeof(struct acpi_facp), GFP_KERNEL); - if (!facp) - return -ENOMEM; - - memset(facp, 0, sizeof(struct acpi_facp)); - facp->hdr.signature = ACPI_FACP_SIG; - facp->hdr.length = sizeof(struct acpi_facp); - facp->int_model = ACPI_PIIX4_INT_MODEL; - facp->sci_int = ACPI_PIIX4_SCI_INT; - facp->smi_cmd = ACPI_PIIX4_SMI_CMD; - facp->acpi_enable = ACPI_PIIX4_ACPI_ENABLE; - facp->acpi_disable = ACPI_PIIX4_ACPI_DISABLE; - facp->s4bios_req = ACPI_PIIX4_S4BIOS_REQ; - facp->pm1a_evt = base + ACPI_PIIX4_PM1_EVT; - facp->pm1a_cnt = base + ACPI_PIIX4_PM1_CNT; - facp->pm2_cnt = ACPI_PIIX4_PM2_CNT; - facp->pm_tmr = base + ACPI_PIIX4_PM_TMR; - facp->gpe0 = base + ACPI_PIIX4_GPE0; - facp->pm1_evt_len = ACPI_PIIX4_PM1_EVT_LEN; - facp->pm1_cnt_len = ACPI_PIIX4_PM1_CNT_LEN; - facp->pm2_cnt_len = ACPI_PIIX4_PM2_CNT_LEN; - facp->pm_tm_len = ACPI_PIIX4_PM_TM_LEN; - facp->gpe0_len = ACPI_PIIX4_GPE0_LEN; - facp->p_lvl2_lat = (__u16) ACPI_INFINITE_LAT; - facp->p_lvl3_lat = (__u16) ACPI_INFINITE_LAT; - - acpi_init_table(&acpi_facp, facp, 0); - acpi_init_table(&acpi_dsdt, NULL, 0); - - acpi_p_blk = base + ACPI_PIIX4_P_BLK; - - return 0; -} - -/* - * Init VIA ACPI device and create a fake FACP - */ -static int __init acpi_init_via(struct pci_dev *dev) -{ - struct acpi_facp *facp; - u32 base; - u8 tmp, irq; - - pci_read_config_byte(dev, 0x41, &tmp); - if (!(tmp & 0x80)) - return -ENODEV; - - base = pci_resource_start(dev, PCI_BRIDGE_RESOURCES); - if (!base) { - base = pci_resource_start(dev, PCI_BASE_ADDRESS_4); - if (!base) - return -ENODEV; - } - - pci_read_config_byte(dev, 0x42, &irq); - - printk(KERN_INFO "ACPI: found %s at 0x%04x\n", dev->name, base); - - facp = kmalloc(sizeof(struct acpi_facp), GFP_KERNEL); - if (!facp) - return -ENOMEM; - - memset(facp, 0, sizeof(struct acpi_facp)); - facp->hdr.signature = ACPI_FACP_SIG; - facp->hdr.length = sizeof(struct acpi_facp); - facp->int_model = ACPI_VIA_INT_MODEL; - facp->sci_int = irq; - facp->smi_cmd = base + ACPI_VIA_SMI_CMD; - facp->acpi_enable = ACPI_VIA_ACPI_ENABLE; - facp->acpi_disable = ACPI_VIA_ACPI_DISABLE; - facp->pm1a_evt = base + ACPI_VIA_PM1_EVT; - facp->pm1a_cnt = base + ACPI_VIA_PM1_CNT; - facp->pm_tmr = base + ACPI_VIA_PM_TMR; - facp->gpe0 = base + ACPI_VIA_GPE0; - - facp->pm1_evt_len = ACPI_VIA_PM1_EVT_LEN; - facp->pm1_cnt_len = ACPI_VIA_PM1_CNT_LEN; - facp->pm_tm_len = ACPI_VIA_PM_TM_LEN; - facp->gpe0_len = ACPI_VIA_GPE0_LEN; - facp->p_lvl2_lat = (__u16) ACPI_INFINITE_LAT; - facp->p_lvl3_lat = (__u16) ACPI_INFINITE_LAT; - - facp->duty_offset = ACPI_VIA_DUTY_OFFSET; - facp->duty_width = ACPI_VIA_DUTY_WIDTH; - - facp->day_alarm = ACPI_VIA_DAY_ALARM; - facp->mon_alarm = ACPI_VIA_MON_ALARM; - facp->century = ACPI_VIA_CENTURY; - - acpi_init_table(&acpi_facp, facp, 0); - acpi_init_table(&acpi_dsdt, NULL, 0); - - acpi_p_blk = base + ACPI_VIA_P_BLK; - - return 0; -} - -typedef enum -{ - CH_UNKNOWN = 0, - CH_INTEL_PIIX4, - CH_VIA_586, - CH_VIA_686A, -} acpi_chip_t; - -/* indexed by value of each enum in acpi_chip_t */ -const static struct -{ - int (*chip_init)(struct pci_dev *dev); -} acpi_chip_info[] = -{ - {NULL,}, - {acpi_init_piix4}, - {acpi_init_via}, - {acpi_init_via}, -}; - -static struct pci_device_id acpi_pci_tbl[] __initdata = -{ - {0x8086, 0x7113, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_INTEL_PIIX4}, - {0x1106, 0x3040, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VIA_586}, - {0x1106, 0x3057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VIA_686A}, - {0,} /* terminate list */ -}; - -static int __init acpi_probe(struct pci_dev *dev, - const struct pci_device_id *id) -{ - return acpi_chip_info[id->driver_data].chip_init(dev); -} - -static struct pci_driver acpi_driver = -{ - name: "acpi", - id_table: acpi_pci_tbl, - probe: acpi_probe, -}; -static int pci_driver_registered = 0; - -/* - * Locate a known ACPI chipset - */ -static int __init acpi_find_chipset(void) -{ - if (pci_register_driver(&acpi_driver) < 1) - return -ENODEV; - - pci_driver_registered = 1; - - return 0; -} - -/* - * Handle an ACPI SCI (fixed or general purpose event) - */ -static void acpi_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - struct acpi_facp *facp = (struct acpi_facp*) acpi_facp.table; - u32 pm1_status, gpe_status, gpe_level, gpe_edge; - unsigned long flags; - - // detect and clear fixed events - pm1_status = (acpi_read_pm1_status(facp) & acpi_read_pm1_enable(facp)); - acpi_write_pm1_status(facp, pm1_status); - - // detect and handle general-purpose events - gpe_status = (acpi_read_gpe_status(facp) & acpi_read_gpe_enable(facp)); - gpe_level = gpe_status & acpi_gpe_level; - if (gpe_level) { - // disable level-triggered events (re-enabled after handling) - acpi_write_gpe_enable(facp, - acpi_read_gpe_enable(facp) & ~gpe_level); - } - gpe_edge = gpe_status & ~gpe_level; - if (gpe_edge) { - // clear edge-triggered events - while (acpi_read_gpe_status(facp) & gpe_edge) - acpi_write_gpe_status(facp, gpe_edge); - } - - // notify process waiting on /dev/acpi - spin_lock_irqsave(&acpi_event_lock, flags); - acpi_pm1_status |= pm1_status; - acpi_gpe_status |= gpe_status; - spin_unlock_irqrestore(&acpi_event_lock, flags); - acpi_event_state = acpi_sleep_state; - wake_up_interruptible(&acpi_event_wait); -} - -/* - * Is SCI to be enabled? - */ -static inline int -acpi_sci_enabled(void) -{ - return !(acpi_opts & ACPI_SCI_DISABLED); -} - -/* - * Is ACPI enabled or not? - */ -static inline int acpi_is_enabled(struct acpi_facp *facp) -{ - return ((acpi_read_pm1_control(facp) & ACPI_SCI_EN) ? 1:0); -} - -/* - * Enable SCI - */ -static int acpi_enable(struct acpi_facp *facp) -{ - if (facp->smi_cmd && acpi_sci_enabled()) - outb(facp->acpi_enable, facp->smi_cmd); - return (acpi_is_enabled(facp) ? 0:-1); -} - -/* - * Disable SCI - */ -static int acpi_disable(struct acpi_facp *facp) -{ - if (facp->smi_cmd && acpi_sci_enabled()) { - // disable and clear any pending events - acpi_write_gpe_enable(facp, 0); - while (acpi_read_gpe_status(facp)) { - acpi_write_gpe_status(facp, - acpi_read_gpe_status(facp)); - } - acpi_write_pm1_enable(facp, 0); - acpi_write_pm1_status(facp, acpi_read_pm1_status(facp)); - - /* writing acpi_disable to smi_cmd would be appropriate - * here but this causes a nasty crash on many systems - */ - } - - return 0; -} - -static inline int bm_activity(struct acpi_facp *facp) -{ - return acpi_read_pm1_status(facp) & ACPI_BM; -} - -static inline void clear_bm_activity(struct acpi_facp *facp) -{ - acpi_write_pm1_status(facp, ACPI_BM); -} - -static void sleep_on_busmaster(struct acpi_facp *facp) -{ - u32 pm1_cntr = acpi_read_pm1_control(facp); - if (pm1_cntr & ACPI_BM_RLD) { - pm1_cntr &= ~ACPI_BM_RLD; - acpi_write_pm1_control(facp, pm1_cntr); - } -} - -static void wake_on_busmaster(struct acpi_facp *facp) -{ - u32 pm1_cntr = acpi_read_pm1_control(facp); - if (!(pm1_cntr & ACPI_BM_RLD)) { - pm1_cntr |= ACPI_BM_RLD; - acpi_write_pm1_control(facp, pm1_cntr); - } - clear_bm_activity(facp); -} - -/* The ACPI timer is just the low 24 bits */ -#define TIME_BEGIN(tmr) inl(tmr) -#define TIME_END(tmr, begin) ((inl(tmr) - (begin)) & 0x00ffffff) - - -/* - * Idle loop (uniprocessor only) - */ -static void acpi_idle(void) -{ - static int sleep_level = 1; - struct acpi_facp *facp = (struct acpi_facp*) acpi_facp.table; - - if (!facp || !facp->pm_tmr || !acpi_p_blk) - goto not_initialized; - - /* - * start from the previous sleep level.. - */ - if (sleep_level == 1) - goto sleep1; - if (sleep_level == 2) - goto sleep2; -sleep3: - sleep_level = 3; - if (!acpi_p_lvl3_tested) { - printk(KERN_INFO "ACPI C3 works\n"); - acpi_p_lvl3_tested = 1; - } - wake_on_busmaster(facp); - if (facp->pm2_cnt) - goto sleep3_with_arbiter; - - for (;;) { - unsigned long time; - unsigned int pm_tmr = facp->pm_tmr; - - __cli(); - if (current->need_resched) - goto out; - if (bm_activity(facp)) - goto sleep2; - - time = TIME_BEGIN(pm_tmr); - inb(acpi_p_blk + ACPI_P_LVL3); - inl(pm_tmr); /* Dummy read, force synchronization with the PMU */ - time = TIME_END(pm_tmr, time); - - __sti(); - cx_statistics(3, time); - if (time < acpi_p_lvl3_lat) - goto sleep2; - } - -sleep3_with_arbiter: - for (;;) { - unsigned long time; - u8 arbiter; - unsigned int pm2_cntr = facp->pm2_cnt; - unsigned int pm_tmr = facp->pm_tmr; - - __cli(); - if (current->need_resched) - goto out; - if (bm_activity(facp)) - goto sleep2; - - time = TIME_BEGIN(pm_tmr); - arbiter = inb(pm2_cntr) & ~ACPI_ARB_DIS; - outb(arbiter | ACPI_ARB_DIS, pm2_cntr); /* Disable arbiter, park on CPU */ - inb(acpi_p_blk + ACPI_P_LVL3); - inl(pm_tmr); /* Dummy read, force synchronization with the PMU */ - time = TIME_END(pm_tmr, time); - outb(arbiter, pm2_cntr); /* Enable arbiter again.. */ - - __sti(); - cx_statistics(3, time); - if (time < acpi_p_lvl3_lat) - goto sleep2; - } - -sleep2: - sleep_level = 2; - if (!acpi_p_lvl2_tested) { - printk(KERN_INFO "ACPI C2 works\n"); - acpi_p_lvl2_tested = 1; - } - wake_on_busmaster(facp); /* Required to track BM activity.. */ - for (;;) { - unsigned long time; - unsigned int pm_tmr = facp->pm_tmr; - - __cli(); - if (current->need_resched) - goto out; - - time = TIME_BEGIN(pm_tmr); - inb(acpi_p_blk + ACPI_P_LVL2); - inl(pm_tmr); /* Dummy read, force synchronization with the PMU */ - time = TIME_END(pm_tmr, time); - - __sti(); - cx_statistics(2, time); - if (time < acpi_p_lvl2_lat) - goto sleep1; - if (bm_activity(facp)) { - clear_bm_activity(facp); - continue; - } - if (time > acpi_enter_lvl3_lat) - goto sleep3; - } - -sleep1: - sleep_level = 1; - sleep_on_busmaster(facp); - for (;;) { - unsigned long time; - unsigned int pm_tmr = facp->pm_tmr; - - __cli(); - if (current->need_resched) - goto out; - time = TIME_BEGIN(pm_tmr); - __asm__ __volatile__("sti ; hlt": : :"memory"); - time = TIME_END(pm_tmr, time); - cx_statistics(1, time); - if (time > acpi_enter_lvl2_lat) - goto sleep2; - } - -not_initialized: - for (;;) { - __cli(); - if (current->need_resched) - goto out; - __asm__ __volatile__("sti ; hlt": : :"memory"); - } - -out: - __sti(); -} - -/* - * Put all devices into specified D-state - */ -static int acpi_enter_dx(acpi_dstate_t state) -{ - int status = 0; - - if (state == ACPI_D0) - status = pm_send_all(PM_RESUME, (void*) state); - else - status = pm_send_all(PM_SUSPEND, (void*) state); - - return status; -} - -/* - * Update system time from real-time clock - */ -static void acpi_update_clock(void) -{ - if (acpi_sleep_start) { - unsigned long delta; - struct timeval tv; - - delta = get_cmos_time() - acpi_sleep_start; - do_gettimeofday(&tv); - tv.tv_sec += delta; - do_settimeofday(&tv); - - acpi_sleep_start = 0; - } -} - -/* - * Enter system sleep state - */ -static int acpi_enter_sx(acpi_sstate_t state) -{ - unsigned long slp_typ; - u16 typa, typb, value; - struct acpi_facp *facp; - - slp_typ = acpi_slp_typ[(int) state]; - if (slp_typ == ACPI_SLP_TYP_DISABLED) - return -EPERM; - - // bits 8-15 are SLP_TYPa, bits 0-7 are SLP_TYPb - typa = (slp_typ >> 8) & 0xff; - typb = slp_typ & 0xff; - - typa = ((typa << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK); - typb = ((typb << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK); - - acpi_sleep_start = get_cmos_time(); - acpi_enter_dx(ACPI_D3); - // disable interrupts globally while suspended - cli(); - acpi_sleep_state = state; - - facp = (struct acpi_facp*) acpi_facp.table; - - // clear wake status - acpi_write_pm1_status(facp, ACPI_WAK); - - // set SLP_TYPa/b and SLP_EN - if (facp->pm1a_cnt) { - value = inw(facp->pm1a_cnt) & ~ACPI_SLP_TYP_MASK; - outw(value | typa | ACPI_SLP_EN, facp->pm1a_cnt); - } - if (facp->pm1b_cnt) { - value = inw(facp->pm1b_cnt) & ~ACPI_SLP_TYP_MASK; - outw(value | typb | ACPI_SLP_EN, facp->pm1b_cnt); - } - - // wait until S1 is entered - while (!(acpi_read_pm1_status(facp) & ACPI_WAK)) ; - // finished sleeping, update system time - acpi_update_clock(); - acpi_enter_dx(ACPI_D0); - // reenable interrupts globally after resume - sti(); - acpi_sleep_state = ACPI_S0; - - return 0; -} - -/* - * Enter soft-off (S5) - */ -static void acpi_power_off(void) -{ - acpi_enter_sx(ACPI_S5); -} - -/* - * Claim I/O port if available - */ -static int acpi_claim(unsigned long start, unsigned long size) -{ - if (start && size) - if (!request_region(start, size, "acpi")) - return -EBUSY; - return 0; -} - -/* - * Claim ACPI I/O ports - */ -static int acpi_claim_ioports(struct acpi_facp *facp) -{ - // we don't get a guarantee of contiguity for any of the ACPI registers - if (acpi_claim(facp->pm1a_evt, facp->pm1_evt_len)) - goto return_ebusy; - if (acpi_claim(facp->pm1b_evt, facp->pm1_evt_len)) - goto release_pm1a_evt; - if (acpi_claim(facp->pm1a_cnt, facp->pm1_cnt_len)) - goto release_pm1b_evt; - if (acpi_claim(facp->pm1b_cnt, facp->pm1_cnt_len)) - goto release_pm1a_cnt; - if (acpi_claim(facp->pm_tmr, facp->pm_tm_len)) - goto release_pm1b_cnt; - if (acpi_claim(facp->gpe0, facp->gpe0_len)) - goto release_pm_tmr; - if (acpi_claim(facp->gpe1, facp->gpe1_len)) - goto release_gpe0; - return 0; -release_gpe0: acpi_release(facp->gpe0, facp->gpe0_len); -release_pm_tmr: acpi_release(facp->pm_tmr, facp->pm_tm_len); -release_pm1b_cnt: acpi_release(facp->pm1b_cnt, facp->pm1_cnt_len); -release_pm1a_cnt: acpi_release(facp->pm1a_cnt, facp->pm1_cnt_len); -release_pm1b_evt: acpi_release(facp->pm1b_evt, facp->pm1_evt_len); -release_pm1a_evt: acpi_release(facp->pm1a_evt, facp->pm1_evt_len); -return_ebusy: return -EBUSY; -} - -/* - * Release I/O port if claimed - */ -static void acpi_release(unsigned long start, unsigned long size) -{ - if (start && size) - release_region(start, size); -} - -/* - * Free ACPI I/O ports - */ -static int acpi_release_ioports(struct acpi_facp *facp) -{ - // we don't get a guarantee of contiguity for any of the ACPI registers - acpi_release(facp->gpe1, facp->gpe1_len); - acpi_release(facp->gpe0, facp->gpe0_len); - acpi_release(facp->pm_tmr, facp->pm_tm_len); - acpi_release(facp->pm1b_cnt, facp->pm1_cnt_len); - acpi_release(facp->pm1a_cnt, facp->pm1_cnt_len); - acpi_release(facp->pm1b_evt, facp->pm1_evt_len); - acpi_release(facp->pm1a_evt, facp->pm1_evt_len); - return 0; -} - -/* - * Determine if modification of value is permitted - */ -static int -acpi_verify_mod(int ctl_name) -{ - switch (ctl_name) { - case ACPI_PM1_ENABLE: - case ACPI_GPE_ENABLE: - case ACPI_GPE_LEVEL: - if (!acpi_sci_enabled()) - return -EPERM; - break; - case ACPI_P_LVL2_LAT: - case ACPI_ENTER_LVL2_LAT: - if (acpi_opts & ACPI_C2_DISABLED) - return -EPERM; - break; - case ACPI_P_LVL3_LAT: - case ACPI_ENTER_LVL3_LAT: - if (acpi_opts & ACPI_C3_DISABLED) - return -EPERM; - break; - case ACPI_S1_SLP_TYP: - case ACPI_SLEEP: - if (acpi_opts & ACPI_S1_DISABLED) - return -EPERM; - break; - case ACPI_S5_SLP_TYP: - if (acpi_opts & ACPI_S5_DISABLED) - return -EPERM; - break; - } - return 0; -} - -/* - * Examine/modify value - */ -static int acpi_do_ulong(ctl_table *ctl, - int write, - struct file *file, - void *buffer, - size_t *len) -{ - char str[2 * sizeof(unsigned long) + 4], *strend; - unsigned long val; - int size; - - if (!write) { - if (file->f_pos) { - *len = 0; - return 0; - } - - val = *(unsigned long*) ctl->data; - size = sprintf(str, "0x%08lx\n", val); - if (*len >= size) { - if (copy_to_user(buffer, str, size)) - return -EFAULT; - *len = size; - } - else - *len = 0; - } - else { - if (acpi_verify_mod(ctl->ctl_name)) - return -EPERM; - - size = sizeof(str) - 1; - if (size > *len) - size = *len; - if (copy_from_user(str, buffer, size)) - return -EFAULT; - str[size] = '\0'; - val = simple_strtoul(str, &strend, 0); - if (strend == str) - return -EINVAL; - *(unsigned long*) ctl->data = val; - } - - file->f_pos += *len; - return 0; -} - -/* - * Determine if user buffer contains a valid table - */ -static int acpi_verify_table(void *buffer, - size_t size, - struct acpi_table_info *info) -{ - struct acpi_table hdr; - size_t table_size; - - if (size < sizeof(struct acpi_table)) - return -EINVAL; - - if (copy_from_user(&hdr, buffer, sizeof(hdr))) - return -EFAULT; - - table_size = (size_t) hdr.length; - if (hdr.signature != info->expected_signature - || table_size < size - || (info->expected_size - && table_size != info->expected_size)) - return -EINVAL; - - return 0; -} - -/* - * Examine/replace an ACPI table - */ -static int acpi_do_table(ctl_table *ctl, - int write, - struct file *file, - void *buffer, - size_t *len) -{ - struct acpi_table_info *info = (struct acpi_table_info *) ctl->data; - u8 *data = NULL; - size_t size = 0; - int error = 0; - - if (!info) { - *len = 0; - return 0; - } - - if (!write) { - // table read - read_lock(&acpi_do_table_lock); - if (info->table && file->f_pos < info->size) { - data = (u8*) info->table + file->f_pos; - size = info->size - file->f_pos; - if (size > *len) - size = *len; - if (copy_to_user(buffer, data, size)) - error = -EFAULT; - } - read_unlock(&acpi_do_table_lock); - } - else if (file->f_pos) { - // table body replacement - write_lock(&acpi_do_table_lock); - if (info->table && file->f_pos < info->size) { - data = (u8*) info->table + file->f_pos; - size = info->size - file->f_pos; - if (size > *len) - size = *len; - if (copy_from_user(data, buffer, size)) - error = -EFAULT; - } - write_unlock(&acpi_do_table_lock); - } - else { - // table header/body replacement - struct acpi_table hdr; - size_t table_size; - - // make sure we are being given a valid table - error = acpi_verify_table(buffer, *len, info); - if (error) - return error; - if (copy_from_user(&hdr, buffer, sizeof(hdr))) - return -EFAULT; - table_size = (size_t) hdr.length; - - write_lock(&acpi_do_table_lock); - - data = (u8*) info->table; - size = *len; - - if (!data || info->mapped || table_size != info->size) { - // allocate a (different sized) table - data = kmalloc(table_size, GFP_KERNEL); - if (data) { - memset(data, 0, table_size); - memcpy(data, &hdr, sizeof(hdr)); - acpi_destroy_table(info); - acpi_init_table(info, data, 0); - } - else - error = -ENOMEM; - } - if (data) - if (copy_from_user(data, buffer, size)) { - acpi_destroy_table(info); - error = -EFAULT; - } - - write_unlock(&acpi_do_table_lock); - } - - if (error) - return error; - - *len = size; - file->f_pos += size; - return 0; -} - -/* - * Examine/modify event register - */ -static int acpi_do_event_reg(ctl_table *ctl, - int write, - struct file *file, - void *buffer, - size_t *len) -{ - struct acpi_facp *facp = (struct acpi_facp*) acpi_facp.table; - char str[2 * sizeof(u32) + 4], *strend; - u32 val, enabling; - int size; - - if (!write) { - if (file->f_pos) { - *len = 0; - return 0; - } - - val = 0; - switch (ctl->ctl_name) { - case ACPI_PM1_ENABLE: - val = acpi_read_pm1_enable(facp); - break; - case ACPI_GPE_ENABLE: - val = acpi_read_gpe_enable(facp); - break; - case ACPI_GPE_LEVEL: - val = acpi_gpe_level; - break; - } - - size = sprintf(str, "0x%08x\n", val); - if (*len >= size) { - if (copy_to_user(buffer, str, size)) - return -EFAULT; - *len = size; - } - else - *len = 0; - } - else - { - if (acpi_verify_mod(ctl->ctl_name)) - return -EPERM; - - // fetch user value - size = sizeof(str) - 1; - if (size > *len) - size = *len; - if (copy_from_user(str, buffer, size)) - return -EFAULT; - str[size] = '\0'; - val = (u32) simple_strtoul(str, &strend, 0); - if (strend == str) - return -EINVAL; - - // store value in register - switch (ctl->ctl_name) { - case ACPI_PM1_ENABLE: - // clear previously disabled events - enabling = (val & ~acpi_read_pm1_enable(facp)); - acpi_write_pm1_status(facp, enabling); - - if (val) { - // enable ACPI unless it is already - if (!acpi_is_enabled(facp)) - acpi_enable(facp); - } - else if (!acpi_read_gpe_enable(facp)) { - // disable ACPI unless it is already - if (acpi_is_enabled(facp)) - acpi_disable(facp); - } - - acpi_write_pm1_enable(facp, val); - break; - case ACPI_GPE_ENABLE: - // clear previously disabled events - enabling = (val - & ~acpi_read_gpe_enable(facp)); - while (acpi_read_gpe_status(facp) & enabling) - acpi_write_gpe_status(facp, enabling); - - if (val) { - // enable ACPI unless it is already - if (!acpi_is_enabled(facp)) - acpi_enable(facp); - } - else if (!acpi_read_pm1_enable(facp)) { - // disable ACPI unless it is already - if (acpi_is_enabled(facp)) - acpi_disable(facp); - } - - acpi_write_gpe_enable(facp, val); - break; - case ACPI_GPE_LEVEL: - acpi_gpe_level = val; - break; - } - } - - file->f_pos += *len; - return 0; -} - -/* - * Wait for next event - */ -static int acpi_do_event(ctl_table *ctl, - int write, - struct file *file, - void *buffer, - size_t *len) -{ - u32 pm1_status = 0, gpe_status = 0; - acpi_sstate_t event_state = 0; - char str[27]; - int size; - - if (write) - return -EPERM; - if (*len < sizeof(str)) { - *len = 0; - return 0; - } - - for (;;) { - unsigned long flags; - - // we need an atomic exchange here - spin_lock_irqsave(&acpi_event_lock, flags); - pm1_status = acpi_pm1_status; - acpi_pm1_status = 0; - gpe_status = acpi_gpe_status; - acpi_gpe_status = 0; - spin_unlock_irqrestore(&acpi_event_lock, flags); - event_state = acpi_event_state; - - if (pm1_status || gpe_status) - break; - - // wait for an event to arrive - interruptible_sleep_on(&acpi_event_wait); - if (signal_pending(current)) - return -ERESTARTSYS; - } - - size = sprintf(str, "0x%08x 0x%08x 0x%01x\n", - pm1_status, - gpe_status, - event_state); - if (copy_to_user(buffer, str, size)) - return -EFAULT; - *len = size; - file->f_pos += size; - - return 0; -} - -/* - * Enter system sleep state - */ -static int acpi_do_sleep(ctl_table *ctl, - int write, - struct file *file, - void *buffer, - size_t *len) -{ - if (!write) { - if (file->f_pos) { - *len = 0; - return 0; - } - } - else - { - if (acpi_verify_mod(ctl->ctl_name) || acpi_enter_sx(ACPI_S1)) - return -EPERM; - } - file->f_pos += *len; - return 0; -} - -/* - * Parse command line options - */ -static int __init acpi_setup(char *str) -{ - while (str && *str) { - struct acpi_option_info *opt = acpi_options; - while (opt->name) { - if (!strncmp(str, opt->name, strlen(opt->name))) { - acpi_opts |= opt->value; - break; - } - opt++; - } - str = strpbrk(str, ","); - if (str) - str += strspn(str, ","); - } - - if (acpi_opts) - printk(KERN_INFO "ACPI: options 0x%08lx\n", acpi_opts); - - return 1; -} - -/* - * kernel/module command line interfaces are both "acpi=OPTION,OPTION,..." - */ -__setup("acpi=", acpi_setup); - -static char * __initdata acpi = NULL; - -MODULE_DESCRIPTION("ACPI driver"); -MODULE_PARM(acpi, "s"); -MODULE_PARM_DESC(acpi, "ACPI driver command line"); - -/* - * Initialize and enable ACPI - */ -int __init acpi_init(void) -{ - struct acpi_facp *facp = NULL; - - if (acpi) - acpi_setup(acpi); - - if (acpi_opts & ACPI_DISABLED) { - return -ENODEV; - } - else if (acpi_opts & ACPI_TABLES_ONLY) { - if (acpi_find_tables()) - return -ENODEV; - } - else if (acpi_opts & ACPI_CHIPSET_ONLY) { - if (acpi_find_chipset()) - return -ENODEV; - } - else { - switch (acpi_find_tables()) { - case 0: - // found valid ACPI tables - break; - case -ENODEV: - // found no ACPI tables, try chipset-specific - if (acpi_find_chipset()) - return -ENODEV; - break; - default: - // found broken ACPI tables - return -ENODEV; - } - } - - facp = (struct acpi_facp*) acpi_facp.table; - - if (PM_IS_ACTIVE()) { - printk(KERN_NOTICE "acpi: APM is already active.\n"); - goto err_out; - } - pm_active = 1; - - /* - * Internally we always keep latencies in timer - * ticks, which is simpler and more consistent (what is - * an uS to us?). Besides, that gives people more - * control in the /proc interfaces. - */ - if (facp->p_lvl2_lat - && facp->p_lvl2_lat <= ACPI_MAX_P_LVL2_LAT - && !acpi_verify_mod(ACPI_P_LVL2_LAT)) { - acpi_p_lvl2_lat = ACPI_uS_TO_TMR_TICKS(facp->p_lvl2_lat); - acpi_enter_lvl2_lat = ACPI_uS_TO_TMR_TICKS(ACPI_TMR_HZ / 1000); - } - if (facp->p_lvl3_lat - && facp->p_lvl3_lat <= ACPI_MAX_P_LVL3_LAT - && !acpi_verify_mod(ACPI_P_LVL3_LAT)) { - acpi_p_lvl3_lat = ACPI_uS_TO_TMR_TICKS(facp->p_lvl3_lat); - acpi_enter_lvl3_lat - = ACPI_uS_TO_TMR_TICKS(facp->p_lvl3_lat * 5); - } - - if (acpi_claim_ioports(facp)) { - printk(KERN_ERR "ACPI: I/O port allocation failed\n"); - goto err_out; - } - - if (facp->sci_int - && acpi_sci_enabled() - && request_irq(facp->sci_int, - acpi_irq, - SA_INTERRUPT | SA_SHIRQ, - "acpi", - &acpi_facp)) { - printk(KERN_ERR "ACPI: SCI (IRQ%d) allocation failed\n", - facp->sci_int); - goto cleanup_ioports; - } - -#ifndef CONFIG_ACPI_S1_SLEEP - acpi_opts |= ACPI_S1_DISABLED; -#endif - - acpi_sysctl = register_sysctl_table(acpi_dir_table, 1); - if (!acpi_sysctl) - goto cleanup_irq; - - pm_power_off = acpi_power_off; - - /* - * Set up the ACPI idle function. Note that we can't really - * do this with multiple CPU's, we'd need a per-CPU ACPI - * device.. - */ -#ifdef CONFIG_SMP - if (smp_num_cpus > 1) - return 0; -#endif - - if (facp->pm_tmr) - pm_idle = acpi_idle; - - return 0; -cleanup_irq: - free_irq(facp->sci_int, &acpi_facp); -cleanup_ioports: - acpi_release_ioports(facp); -err_out: - if (pci_driver_registered) - pci_unregister_driver(&acpi_driver); - acpi_destroy_tables(); - - return -ENODEV; -} - -/* - * Disable and deinitialize ACPI - */ -void __exit acpi_exit(void) -{ - struct acpi_facp *facp = (struct acpi_facp*) acpi_facp.table; - - pm_idle = NULL; - pm_power_off = NULL; - - unregister_sysctl_table(acpi_sysctl); - acpi_disable(facp); - acpi_release_ioports(facp); - - if (facp->sci_int && acpi_sci_enabled()) - free_irq(facp->sci_int, &acpi_facp); - - acpi_destroy_tables(); - - if (pci_driver_registered) - pci_unregister_driver(&acpi_driver); - - pm_active = 0; -} - -module_init(acpi_init); -module_exit(acpi_exit); diff -u --recursive --new-file v2.4.0-test12/linux/arch/i386/kernel/bluesmoke.c linux/arch/i386/kernel/bluesmoke.c --- v2.4.0-test12/linux/arch/i386/kernel/bluesmoke.c Sun Nov 19 18:44:02 2000 +++ linux/arch/i386/kernel/bluesmoke.c Fri Dec 29 14:07:20 2000 @@ -75,7 +75,7 @@ if( c->x86_vendor != X86_VENDOR_INTEL ) return; - if( !test_bit(X86_FEATURE_TSC, &c->x86_capability) ) + if( !test_bit(X86_FEATURE_MCE, &c->x86_capability) ) return; if( !test_bit(X86_FEATURE_MCA, &c->x86_capability) ) diff -u --recursive --new-file v2.4.0-test12/linux/arch/i386/kernel/cpuid.c linux/arch/i386/kernel/cpuid.c --- v2.4.0-test12/linux/arch/i386/kernel/cpuid.c Tue Jun 20 13:58:42 2000 +++ linux/arch/i386/kernel/cpuid.c Sun Dec 31 09:23:51 2000 @@ -153,6 +153,7 @@ void __exit cpuid_exit(void) { + unregister_chrdev(CPUID_MAJOR, "cpu/cpuid"); } module_init(cpuid_init); diff -u --recursive --new-file v2.4.0-test12/linux/arch/i386/kernel/dmi_scan.c linux/arch/i386/kernel/dmi_scan.c --- v2.4.0-test12/linux/arch/i386/kernel/dmi_scan.c Mon Dec 11 17:59:43 2000 +++ linux/arch/i386/kernel/dmi_scan.c Fri Dec 29 14:07:20 2000 @@ -1,4 +1,3 @@ -#include #include #include #include diff -u --recursive --new-file v2.4.0-test12/linux/arch/i386/kernel/ldt.c linux/arch/i386/kernel/ldt.c --- v2.4.0-test12/linux/arch/i386/kernel/ldt.c Sat May 20 10:39:58 2000 +++ linux/arch/i386/kernel/ldt.c Fri Dec 29 14:07:20 2000 @@ -31,7 +31,7 @@ struct mm_struct * mm = current->mm; err = 0; - if (!mm->segments) + if (!mm->context.segments) goto out; size = LDT_ENTRIES*LDT_ENTRY_SIZE; @@ -39,7 +39,7 @@ size = bytecount; err = size; - if (copy_to_user(ptr, mm->segments, size)) + if (copy_to_user(ptr, mm->context.segments, size)) err = -EFAULT; out: return err; @@ -87,13 +87,12 @@ * limited by MAX_LDT_DESCRIPTORS. */ down(&mm->mmap_sem); - if (!mm->segments) { - + if (!mm->context.segments) { error = -ENOMEM; - mm->segments = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE); - if (!mm->segments) + mm->context.segments = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE); + if (!mm->context.segments) goto out_unlock; - memset(mm->segments, 0, LDT_ENTRIES*LDT_ENTRY_SIZE); + memset(mm->context.segments, 0, LDT_ENTRIES*LDT_ENTRY_SIZE); if (atomic_read(&mm->mm_users) > 1) printk(KERN_WARNING "LDT allocated for cloned task!\n"); @@ -104,7 +103,7 @@ load_LDT(mm); } - lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->segments); + lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->context.segments); /* Allow LDTs to be cleared by the user. */ if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { diff -u --recursive --new-file v2.4.0-test12/linux/arch/i386/kernel/msr.c linux/arch/i386/kernel/msr.c --- v2.4.0-test12/linux/arch/i386/kernel/msr.c Sun Nov 19 18:44:02 2000 +++ linux/arch/i386/kernel/msr.c Sun Dec 31 09:24:08 2000 @@ -261,6 +261,7 @@ void __exit msr_exit(void) { + unregister_chrdev(MSR_MAJOR, "cpu/msr"); } module_init(msr_init); diff -u --recursive --new-file v2.4.0-test12/linux/arch/i386/kernel/pci-irq.c linux/arch/i386/kernel/pci-irq.c --- v2.4.0-test12/linux/arch/i386/kernel/pci-irq.c Mon Dec 11 17:59:43 2000 +++ linux/arch/i386/kernel/pci-irq.c Fri Dec 29 14:07:20 2000 @@ -325,6 +325,30 @@ return 1; } +/* + * ServerWorks: PCI interrupts mapped to system IRQ lines through Index + * and Redirect I/O registers (0x0c00 and 0x0c01). The Index register + * format is (PCIIRQ## | 0x10), e.g.: PCIIRQ10=0x1a. The Redirect + * register is a straight binary coding of desired PIC IRQ (low nibble). + * + * The 'link' value in the PIRQ table is already in the correct format + * for the Index register. There are some special index values: + * 0x00 for ACPI (SCI), 0x01 for USB, 0x02 for IDE0, 0x04 for IDE1, + * and 0x03 for SMBus. + */ +static int pirq_serverworks_get(struct pci_dev *router, struct pci_dev *dev, int pirq) +{ + outb_p(pirq, 0xc00); + return inb(0xc01) & 0xf; +} + +static int pirq_serverworks_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) +{ + outb_p(pirq, 0xc00); + outb_p(irq, 0xc01); + return 1; +} + #ifdef CONFIG_PCI_BIOS static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) @@ -357,6 +381,9 @@ { "NatSemi", PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, pirq_cyrix_get, pirq_cyrix_set }, { "SIS", PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, pirq_sis_get, pirq_sis_set }, { "VLSI 82C534", PCI_VENDOR_ID_VLSI, PCI_DEVICE_ID_VLSI_82C534, pirq_vlsi_get, pirq_vlsi_set }, + { "ServerWorks", PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4, + pirq_serverworks_get, pirq_serverworks_set }, + { "default", 0, 0, NULL, NULL } }; diff -u --recursive --new-file v2.4.0-test12/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- v2.4.0-test12/linux/arch/i386/kernel/process.c Mon Dec 11 17:59:43 2000 +++ linux/arch/i386/kernel/process.c Sat Dec 30 09:58:55 2000 @@ -414,13 +414,13 @@ */ void release_segments(struct mm_struct *mm) { - void * ldt = mm->segments; + void * ldt = mm->context.segments; /* * free the LDT */ if (ldt) { - mm->segments = NULL; + mm->context.segments = NULL; clear_LDT(); vfree(ldt); } @@ -478,7 +478,7 @@ void release_thread(struct task_struct *dead_task) { if (dead_task->mm) { - void * ldt = dead_task->mm->segments; + void * ldt = dead_task->mm->context.segments; // temporary debugging check if (ldt) { @@ -495,27 +495,22 @@ */ void copy_segments(struct task_struct *p, struct mm_struct *new_mm) { - struct mm_struct * old_mm = current->mm; - void * old_ldt = old_mm->segments, * ldt; + struct mm_struct * old_mm; + void *old_ldt, *ldt; - if (!old_ldt) { + ldt = NULL; + old_mm = current->mm; + if (old_mm && (old_ldt = old_mm->context.segments) != NULL) { /* - * default LDT - use the one from init_task + * Completely new LDT, we initialize it from the parent: */ - new_mm->segments = NULL; - return; + ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE); + if (!ldt) + printk(KERN_WARNING "ldt allocation failed\n"); + else + memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE); } - - /* - * Completely new LDT, we initialize it from the parent: - */ - ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE); - if (!ldt) - printk(KERN_WARNING "ldt allocation failed\n"); - else - memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE); - new_mm->segments = ldt; - return; + new_mm->context.segments = ldt; } /* diff -u --recursive --new-file v2.4.0-test12/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.4.0-test12/linux/arch/i386/kernel/setup.c Mon Dec 11 17:59:43 2000 +++ linux/arch/i386/kernel/setup.c Sun Dec 31 10:26:18 2000 @@ -477,7 +477,7 @@ if (start < 0x100000ULL && end > 0xA0000ULL) { if (start < 0xA0000ULL) add_memory_region(start, 0xA0000ULL-start, type); - if (end < 0x100000ULL) + if (end <= 0x100000ULL) continue; start = 0x100000ULL; size = end - start; @@ -518,7 +518,7 @@ e820.nr_map = 0; add_memory_region(0, LOWMEMSIZE(), E820_RAM); - add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM); + add_memory_region(HIGH_MEMORY, (mem_size << 10) - HIGH_MEMORY, E820_RAM); } printk("BIOS-provided physical RAM map:\n"); print_memory_map(who); @@ -1149,7 +1149,7 @@ if (ccr5 & 2) { /* possible wrong calibration done */ printk(KERN_INFO "Recalibrating delay loop with SLOP bit reset\n"); calibrate_delay(); - c->loops_per_sec = loops_per_sec; + c->loops_per_jiffy = loops_per_jiffy; } } } @@ -1553,7 +1553,7 @@ /* L1 D cache */ l1d += 16; break; - default: + default:; /* TLB, or unknown */ } break; @@ -1884,7 +1884,7 @@ int junk, i; u32 xlvl, tfms; - c->loops_per_sec = loops_per_sec; + c->loops_per_jiffy = loops_per_jiffy; c->x86_cache_size = -1; c->x86_vendor = X86_VENDOR_UNKNOWN; c->cpuid_level = -1; /* CPUID not detected */ @@ -2188,8 +2188,8 @@ p += sprintf(p, " %s", x86_cap_flags[i]); p += sprintf(p, "\nbogomips\t: %lu.%02lu\n\n", - (c->loops_per_sec+2500)/500000, - ((c->loops_per_sec+2500)/5000) % 100); + c->loops_per_jiffy/(500000/HZ), + (c->loops_per_jiffy/(5000/HZ)) % 100); } return p - buffer; } diff -u --recursive --new-file v2.4.0-test12/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c --- v2.4.0-test12/linux/arch/i386/kernel/smp.c Tue Oct 31 12:42:26 2000 +++ linux/arch/i386/kernel/smp.c Fri Dec 29 14:35:47 2000 @@ -278,7 +278,16 @@ unsigned long cpu = smp_processor_id(); if (!test_bit(cpu, &flush_cpumask)) - BUG(); + return; + /* + * This was a BUG() but until someone can quote me the + * line from the intel manual that guarantees an IPI to + * multiple CPUs is retried _only_ on the erroring CPUs + * its staying as a return + * + * BUG(); + */ + if (flush_mm == cpu_tlbstate[cpu].active_mm) { if (cpu_tlbstate[cpu].state == TLBSTATE_OK) { if (flush_va == FLUSH_ALL) diff -u --recursive --new-file v2.4.0-test12/linux/arch/i386/kernel/smpboot.c linux/arch/i386/kernel/smpboot.c --- v2.4.0-test12/linux/arch/i386/kernel/smpboot.c Mon Dec 11 17:59:43 2000 +++ linux/arch/i386/kernel/smpboot.c Sun Dec 31 10:26:18 2000 @@ -694,6 +694,11 @@ apic_write_around(APIC_ICR, APIC_DM_STARTUP | (start_eip >> 12)); + /* + * Give the other CPU some time to accept the IPI. + */ + udelay(300); + Dprintk("Startup point 1.\n"); Dprintk("Waiting for send to finish...\n"); @@ -979,11 +984,11 @@ unsigned long bogosum = 0; for (cpu = 0; cpu < NR_CPUS; cpu++) if (cpu_online_map & (1<mm->segments)[(s) >> 3]) +#define LDT_DESCRIPTOR(s) (((struct desc_struct *)current->mm->context.segments)[(s) >> 3]) #define SEG_D_SIZE(x) ((x).b & (3 << 21)) #define SEG_G_BIT(x) ((x).b & (1 << 23)) #define SEG_GRANULARITY(x) (((x).b & (1 << 23)) ? 4096 : 1) diff -u --recursive --new-file v2.4.0-test12/linux/arch/i386/mm/Makefile linux/arch/i386/mm/Makefile --- v2.4.0-test12/linux/arch/i386/mm/Makefile Tue Oct 19 10:22:20 1999 +++ linux/arch/i386/mm/Makefile Fri Dec 29 14:07:20 2000 @@ -8,6 +8,7 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := mm.o -O_OBJS := init.o fault.o ioremap.o extable.o + +obj-y := init.o fault.o ioremap.o extable.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test12/linux/arch/m68k/amiga/Makefile linux/arch/m68k/amiga/Makefile --- v2.4.0-test12/linux/arch/m68k/amiga/Makefile Thu Jul 30 11:08:19 1998 +++ linux/arch/m68k/amiga/Makefile Fri Dec 29 14:07:20 2000 @@ -8,11 +8,11 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := amiga.o -O_OBJS := config.o amiints.o cia.o chipram.o amisound.o -OX_OBJS := amiga_ksyms.o -ifdef CONFIG_AMIGA_PCMCIA -O_OBJS := $(O_OBJS) pcmcia.o -endif +export-objs := amiga_ksyms.o + +obj-y := config.o amiints.o cia.o chipram.o amisound.o amiga_ksyms.o + +obj-$(CONFIG_AMIGA_PCMCIA) += pcmcia.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test12/linux/arch/m68k/apollo/Makefile linux/arch/m68k/apollo/Makefile --- v2.4.0-test12/linux/arch/m68k/apollo/Makefile Wed Jan 26 12:44:20 2000 +++ linux/arch/m68k/apollo/Makefile Fri Dec 29 14:07:20 2000 @@ -8,7 +8,7 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := apollo.o -O_OBJS := config.o dn_ints.o dma.o \ +obj-y := config.o dn_ints.o dma.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test12/linux/arch/m68k/atari/Makefile linux/arch/m68k/atari/Makefile --- v2.4.0-test12/linux/arch/m68k/atari/Makefile Wed Jan 26 12:44:20 2000 +++ linux/arch/m68k/atari/Makefile Fri Dec 29 14:07:20 2000 @@ -8,14 +8,14 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := atari.o -O_OBJS := config.o time.o debug.o atakeyb.o ataints.o stdma.o atasound.o \ - joystick.o stram.o -OX_OBJS := atari_ksyms.o + +export-objs := atari_ksyms.o + +obj-y := config.o time.o debug.o atakeyb.o ataints.o stdma.o \ + atasound.o joystick.o stram.o atari_ksyms.o ifdef CONFIG_PCI -ifdef CONFIG_HADES -O_OBJS += hades-pci.o -endif +obj-$(CONFIG_HADES) += hades-pci.o endif include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test12/linux/arch/m68k/bvme6000/Makefile linux/arch/m68k/bvme6000/Makefile --- v2.4.0-test12/linux/arch/m68k/bvme6000/Makefile Sat Jun 13 13:14:31 1998 +++ linux/arch/m68k/bvme6000/Makefile Fri Dec 29 14:07:20 2000 @@ -8,7 +8,7 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := bvme6000.o -O_OBJS := config.o bvmeints.o rtc.o -#OX_OBJS = ksyms.o + +obj-y := config.o bvmeints.o rtc.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test12/linux/arch/m68k/hp300/Makefile linux/arch/m68k/hp300/Makefile --- v2.4.0-test12/linux/arch/m68k/hp300/Makefile Wed Sep 2 09:39:18 1998 +++ linux/arch/m68k/hp300/Makefile Fri Dec 29 14:07:20 2000 @@ -8,10 +8,11 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := hp300.o -O_OBJS := ksyms.o config.o ints.o time.o reboot.o -ifdef CONFIG_VT -O_OBJS += hil.o -endif +export-objs := ksyms.o + +obj-y := ksyms.o config.o ints.o time.o reboot.o + +obj-$(CONFIG_VT) += hil.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test12/linux/arch/m68k/ifpsp060/src/README-SRC linux/arch/m68k/ifpsp060/src/README-SRC --- v2.4.0-test12/linux/arch/m68k/ifpsp060/src/README-SRC Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/ifpsp060/src/README-SRC Fri Dec 29 14:07:20 2000 @@ -0,0 +1,12 @@ +This is the original source code from Motorola for the 68060 processor +support code, providing emulation for rarely used m68k instructions +not implemented in the 68060 silicon. + +The code provided here will not assemble out of the box using the GNU +assembler, however it is being included in order to comply with the +GNU General Public License. + +You don't need to actually assemble these files in order to compile a +workin m68k kernel, the precompiled .sa files in arch/m68k/ifpsp060 +are sufficient and were generated from these source files by +Motorola. diff -u --recursive --new-file v2.4.0-test12/linux/arch/m68k/ifpsp060/src/fplsp.S linux/arch/m68k/ifpsp060/src/fplsp.S --- v2.4.0-test12/linux/arch/m68k/ifpsp060/src/fplsp.S Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/ifpsp060/src/fplsp.S Fri Dec 29 14:07:20 2000 @@ -0,0 +1,10980 @@ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP +M68000 Hi-Performance Microprocessor Division +M68060 Software Package +Production Release P1.00 -- October 10, 1994 + +M68060 Software Package Copyright © 1993, 1994 Motorola Inc. All rights reserved. + +THE SOFTWARE is provided on an "AS IS" basis and without warranty. +To the maximum extent permitted by applicable law, +MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, +INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE +and any warranty against infringement with regard to the SOFTWARE +(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials. + +To the maximum extent permitted by applicable law, +IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER +(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, +BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) +ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE. +Motorola assumes no responsibility for the maintenance and support of the SOFTWARE. + +You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE +so long as this entire notice is retained without alteration in any modified and/or +redistributed versions, and that such modified versions are clearly identified as such. +No licenses are granted by implication, estoppel or otherwise under any patents +or trademarks of Motorola, Inc. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# lfptop.s: +# This file is appended to the top of the 060ILSP package +# and contains the entry points into the package. The user, in +# effect, branches to one of the branch table entries located here. +# + + bra.l _facoss_ + short 0x0000 + bra.l _facosd_ + short 0x0000 + bra.l _facosx_ + short 0x0000 + + bra.l _fasins_ + short 0x0000 + bra.l _fasind_ + short 0x0000 + bra.l _fasinx_ + short 0x0000 + + bra.l _fatans_ + short 0x0000 + bra.l _fatand_ + short 0x0000 + bra.l _fatanx_ + short 0x0000 + + bra.l _fatanhs_ + short 0x0000 + bra.l _fatanhd_ + short 0x0000 + bra.l _fatanhx_ + short 0x0000 + + bra.l _fcoss_ + short 0x0000 + bra.l _fcosd_ + short 0x0000 + bra.l _fcosx_ + short 0x0000 + + bra.l _fcoshs_ + short 0x0000 + bra.l _fcoshd_ + short 0x0000 + bra.l _fcoshx_ + short 0x0000 + + bra.l _fetoxs_ + short 0x0000 + bra.l _fetoxd_ + short 0x0000 + bra.l _fetoxx_ + short 0x0000 + + bra.l _fetoxm1s_ + short 0x0000 + bra.l _fetoxm1d_ + short 0x0000 + bra.l _fetoxm1x_ + short 0x0000 + + bra.l _fgetexps_ + short 0x0000 + bra.l _fgetexpd_ + short 0x0000 + bra.l _fgetexpx_ + short 0x0000 + + bra.l _fgetmans_ + short 0x0000 + bra.l _fgetmand_ + short 0x0000 + bra.l _fgetmanx_ + short 0x0000 + + bra.l _flog10s_ + short 0x0000 + bra.l _flog10d_ + short 0x0000 + bra.l _flog10x_ + short 0x0000 + + bra.l _flog2s_ + short 0x0000 + bra.l _flog2d_ + short 0x0000 + bra.l _flog2x_ + short 0x0000 + + bra.l _flogns_ + short 0x0000 + bra.l _flognd_ + short 0x0000 + bra.l _flognx_ + short 0x0000 + + bra.l _flognp1s_ + short 0x0000 + bra.l _flognp1d_ + short 0x0000 + bra.l _flognp1x_ + short 0x0000 + + bra.l _fmods_ + short 0x0000 + bra.l _fmodd_ + short 0x0000 + bra.l _fmodx_ + short 0x0000 + + bra.l _frems_ + short 0x0000 + bra.l _fremd_ + short 0x0000 + bra.l _fremx_ + short 0x0000 + + bra.l _fscales_ + short 0x0000 + bra.l _fscaled_ + short 0x0000 + bra.l _fscalex_ + short 0x0000 + + bra.l _fsins_ + short 0x0000 + bra.l _fsind_ + short 0x0000 + bra.l _fsinx_ + short 0x0000 + + bra.l _fsincoss_ + short 0x0000 + bra.l _fsincosd_ + short 0x0000 + bra.l _fsincosx_ + short 0x0000 + + bra.l _fsinhs_ + short 0x0000 + bra.l _fsinhd_ + short 0x0000 + bra.l _fsinhx_ + short 0x0000 + + bra.l _ftans_ + short 0x0000 + bra.l _ftand_ + short 0x0000 + bra.l _ftanx_ + short 0x0000 + + bra.l _ftanhs_ + short 0x0000 + bra.l _ftanhd_ + short 0x0000 + bra.l _ftanhx_ + short 0x0000 + + bra.l _ftentoxs_ + short 0x0000 + bra.l _ftentoxd_ + short 0x0000 + bra.l _ftentoxx_ + short 0x0000 + + bra.l _ftwotoxs_ + short 0x0000 + bra.l _ftwotoxd_ + short 0x0000 + bra.l _ftwotoxx_ + short 0x0000 + + bra.l _fabss_ + short 0x0000 + bra.l _fabsd_ + short 0x0000 + bra.l _fabsx_ + short 0x0000 + + bra.l _fadds_ + short 0x0000 + bra.l _faddd_ + short 0x0000 + bra.l _faddx_ + short 0x0000 + + bra.l _fdivs_ + short 0x0000 + bra.l _fdivd_ + short 0x0000 + bra.l _fdivx_ + short 0x0000 + + bra.l _fints_ + short 0x0000 + bra.l _fintd_ + short 0x0000 + bra.l _fintx_ + short 0x0000 + + bra.l _fintrzs_ + short 0x0000 + bra.l _fintrzd_ + short 0x0000 + bra.l _fintrzx_ + short 0x0000 + + bra.l _fmuls_ + short 0x0000 + bra.l _fmuld_ + short 0x0000 + bra.l _fmulx_ + short 0x0000 + + bra.l _fnegs_ + short 0x0000 + bra.l _fnegd_ + short 0x0000 + bra.l _fnegx_ + short 0x0000 + + bra.l _fsqrts_ + short 0x0000 + bra.l _fsqrtd_ + short 0x0000 + bra.l _fsqrtx_ + short 0x0000 + + bra.l _fsubs_ + short 0x0000 + bra.l _fsubd_ + short 0x0000 + bra.l _fsubx_ + short 0x0000 + +# leave room for future possible additions + align 0x400 + +# +# This file contains a set of define statements for constants +# in order to promote readability within the corecode itself. +# + +set LOCAL_SIZE, 192 # stack frame size(bytes) +set LV, -LOCAL_SIZE # stack offset + +set EXC_SR, 0x4 # stack status register +set EXC_PC, 0x6 # stack pc +set EXC_VOFF, 0xa # stacked vector offset +set EXC_EA, 0xc # stacked + +set EXC_FP, 0x0 # frame pointer + +set EXC_AREGS, -68 # offset of all address regs +set EXC_DREGS, -100 # offset of all data regs +set EXC_FPREGS, -36 # offset of all fp regs + +set EXC_A7, EXC_AREGS+(7*4) # offset of saved a7 +set OLD_A7, EXC_AREGS+(6*4) # extra copy of saved a7 +set EXC_A6, EXC_AREGS+(6*4) # offset of saved a6 +set EXC_A5, EXC_AREGS+(5*4) +set EXC_A4, EXC_AREGS+(4*4) +set EXC_A3, EXC_AREGS+(3*4) +set EXC_A2, EXC_AREGS+(2*4) +set EXC_A1, EXC_AREGS+(1*4) +set EXC_A0, EXC_AREGS+(0*4) +set EXC_D7, EXC_DREGS+(7*4) +set EXC_D6, EXC_DREGS+(6*4) +set EXC_D5, EXC_DREGS+(5*4) +set EXC_D4, EXC_DREGS+(4*4) +set EXC_D3, EXC_DREGS+(3*4) +set EXC_D2, EXC_DREGS+(2*4) +set EXC_D1, EXC_DREGS+(1*4) +set EXC_D0, EXC_DREGS+(0*4) + +set EXC_FP0, EXC_FPREGS+(0*12) # offset of saved fp0 +set EXC_FP1, EXC_FPREGS+(1*12) # offset of saved fp1 +set EXC_FP2, EXC_FPREGS+(2*12) # offset of saved fp2 (not used) + +set FP_SCR1, LV+80 # fp scratch 1 +set FP_SCR1_EX, FP_SCR1+0 +set FP_SCR1_SGN, FP_SCR1+2 +set FP_SCR1_HI, FP_SCR1+4 +set FP_SCR1_LO, FP_SCR1+8 + +set FP_SCR0, LV+68 # fp scratch 0 +set FP_SCR0_EX, FP_SCR0+0 +set FP_SCR0_SGN, FP_SCR0+2 +set FP_SCR0_HI, FP_SCR0+4 +set FP_SCR0_LO, FP_SCR0+8 + +set FP_DST, LV+56 # fp destination operand +set FP_DST_EX, FP_DST+0 +set FP_DST_SGN, FP_DST+2 +set FP_DST_HI, FP_DST+4 +set FP_DST_LO, FP_DST+8 + +set FP_SRC, LV+44 # fp source operand +set FP_SRC_EX, FP_SRC+0 +set FP_SRC_SGN, FP_SRC+2 +set FP_SRC_HI, FP_SRC+4 +set FP_SRC_LO, FP_SRC+8 + +set USER_FPIAR, LV+40 # FP instr address register + +set USER_FPSR, LV+36 # FP status register +set FPSR_CC, USER_FPSR+0 # FPSR condition codes +set FPSR_QBYTE, USER_FPSR+1 # FPSR qoutient byte +set FPSR_EXCEPT, USER_FPSR+2 # FPSR exception status byte +set FPSR_AEXCEPT, USER_FPSR+3 # FPSR accrued exception byte + +set USER_FPCR, LV+32 # FP control register +set FPCR_ENABLE, USER_FPCR+2 # FPCR exception enable +set FPCR_MODE, USER_FPCR+3 # FPCR rounding mode control + +set L_SCR3, LV+28 # integer scratch 3 +set L_SCR2, LV+24 # integer scratch 2 +set L_SCR1, LV+20 # integer scratch 1 + +set STORE_FLG, LV+19 # flag: operand store (ie. not fcmp/ftst) + +set EXC_TEMP2, LV+24 # temporary space +set EXC_TEMP, LV+16 # temporary space + +set DTAG, LV+15 # destination operand type +set STAG, LV+14 # source operand type + +set SPCOND_FLG, LV+10 # flag: special case (see below) + +set EXC_CC, LV+8 # saved condition codes +set EXC_EXTWPTR, LV+4 # saved current PC (active) +set EXC_EXTWORD, LV+2 # saved extension word +set EXC_CMDREG, LV+2 # saved extension word +set EXC_OPWORD, LV+0 # saved operation word + +################################ + +# Helpful macros + +set FTEMP, 0 # offsets within an +set FTEMP_EX, 0 # extended precision +set FTEMP_SGN, 2 # value saved in memory. +set FTEMP_HI, 4 +set FTEMP_LO, 8 +set FTEMP_GRS, 12 + +set LOCAL, 0 # offsets within an +set LOCAL_EX, 0 # extended precision +set LOCAL_SGN, 2 # value saved in memory. +set LOCAL_HI, 4 +set LOCAL_LO, 8 +set LOCAL_GRS, 12 + +set DST, 0 # offsets within an +set DST_EX, 0 # extended precision +set DST_HI, 4 # value saved in memory. +set DST_LO, 8 + +set SRC, 0 # offsets within an +set SRC_EX, 0 # extended precision +set SRC_HI, 4 # value saved in memory. +set SRC_LO, 8 + +set SGL_LO, 0x3f81 # min sgl prec exponent +set SGL_HI, 0x407e # max sgl prec exponent +set DBL_LO, 0x3c01 # min dbl prec exponent +set DBL_HI, 0x43fe # max dbl prec exponent +set EXT_LO, 0x0 # min ext prec exponent +set EXT_HI, 0x7ffe # max ext prec exponent + +set EXT_BIAS, 0x3fff # extended precision bias +set SGL_BIAS, 0x007f # single precision bias +set DBL_BIAS, 0x03ff # double precision bias + +set NORM, 0x00 # operand type for STAG/DTAG +set ZERO, 0x01 # operand type for STAG/DTAG +set INF, 0x02 # operand type for STAG/DTAG +set QNAN, 0x03 # operand type for STAG/DTAG +set DENORM, 0x04 # operand type for STAG/DTAG +set SNAN, 0x05 # operand type for STAG/DTAG +set UNNORM, 0x06 # operand type for STAG/DTAG + +################## +# FPSR/FPCR bits # +################## +set neg_bit, 0x3 # negative result +set z_bit, 0x2 # zero result +set inf_bit, 0x1 # infinite result +set nan_bit, 0x0 # NAN result + +set q_sn_bit, 0x7 # sign bit of quotient byte + +set bsun_bit, 7 # branch on unordered +set snan_bit, 6 # signalling NAN +set operr_bit, 5 # operand error +set ovfl_bit, 4 # overflow +set unfl_bit, 3 # underflow +set dz_bit, 2 # divide by zero +set inex2_bit, 1 # inexact result 2 +set inex1_bit, 0 # inexact result 1 + +set aiop_bit, 7 # accrued inexact operation bit +set aovfl_bit, 6 # accrued overflow bit +set aunfl_bit, 5 # accrued underflow bit +set adz_bit, 4 # accrued dz bit +set ainex_bit, 3 # accrued inexact bit + +############################# +# FPSR individual bit masks # +############################# +set neg_mask, 0x08000000 # negative bit mask (lw) +set inf_mask, 0x02000000 # infinity bit mask (lw) +set z_mask, 0x04000000 # zero bit mask (lw) +set nan_mask, 0x01000000 # nan bit mask (lw) + +set neg_bmask, 0x08 # negative bit mask (byte) +set inf_bmask, 0x02 # infinity bit mask (byte) +set z_bmask, 0x04 # zero bit mask (byte) +set nan_bmask, 0x01 # nan bit mask (byte) + +set bsun_mask, 0x00008000 # bsun exception mask +set snan_mask, 0x00004000 # snan exception mask +set operr_mask, 0x00002000 # operr exception mask +set ovfl_mask, 0x00001000 # overflow exception mask +set unfl_mask, 0x00000800 # underflow exception mask +set dz_mask, 0x00000400 # dz exception mask +set inex2_mask, 0x00000200 # inex2 exception mask +set inex1_mask, 0x00000100 # inex1 exception mask + +set aiop_mask, 0x00000080 # accrued illegal operation +set aovfl_mask, 0x00000040 # accrued overflow +set aunfl_mask, 0x00000020 # accrued underflow +set adz_mask, 0x00000010 # accrued divide by zero +set ainex_mask, 0x00000008 # accrued inexact + +###################################### +# FPSR combinations used in the FPSP # +###################################### +set dzinf_mask, inf_mask+dz_mask+adz_mask +set opnan_mask, nan_mask+operr_mask+aiop_mask +set nzi_mask, 0x01ffffff #clears N, Z, and I +set unfinx_mask, unfl_mask+inex2_mask+aunfl_mask+ainex_mask +set unf2inx_mask, unfl_mask+inex2_mask+ainex_mask +set ovfinx_mask, ovfl_mask+inex2_mask+aovfl_mask+ainex_mask +set inx1a_mask, inex1_mask+ainex_mask +set inx2a_mask, inex2_mask+ainex_mask +set snaniop_mask, nan_mask+snan_mask+aiop_mask +set snaniop2_mask, snan_mask+aiop_mask +set naniop_mask, nan_mask+aiop_mask +set neginf_mask, neg_mask+inf_mask +set infaiop_mask, inf_mask+aiop_mask +set negz_mask, neg_mask+z_mask +set opaop_mask, operr_mask+aiop_mask +set unfl_inx_mask, unfl_mask+aunfl_mask+ainex_mask +set ovfl_inx_mask, ovfl_mask+aovfl_mask+ainex_mask + +######### +# misc. # +######### +set rnd_stky_bit, 29 # stky bit pos in longword + +set sign_bit, 0x7 # sign bit +set signan_bit, 0x6 # signalling nan bit + +set sgl_thresh, 0x3f81 # minimum sgl exponent +set dbl_thresh, 0x3c01 # minimum dbl exponent + +set x_mode, 0x0 # extended precision +set s_mode, 0x4 # single precision +set d_mode, 0x8 # double precision + +set rn_mode, 0x0 # round-to-nearest +set rz_mode, 0x1 # round-to-zero +set rm_mode, 0x2 # round-tp-minus-infinity +set rp_mode, 0x3 # round-to-plus-infinity + +set mantissalen, 64 # length of mantissa in bits + +set BYTE, 1 # len(byte) == 1 byte +set WORD, 2 # len(word) == 2 bytes +set LONG, 4 # len(longword) == 2 bytes + +set BSUN_VEC, 0xc0 # bsun vector offset +set INEX_VEC, 0xc4 # inexact vector offset +set DZ_VEC, 0xc8 # dz vector offset +set UNFL_VEC, 0xcc # unfl vector offset +set OPERR_VEC, 0xd0 # operr vector offset +set OVFL_VEC, 0xd4 # ovfl vector offset +set SNAN_VEC, 0xd8 # snan vector offset + +########################### +# SPecial CONDition FLaGs # +########################### +set ftrapcc_flg, 0x01 # flag bit: ftrapcc exception +set fbsun_flg, 0x02 # flag bit: bsun exception +set mia7_flg, 0x04 # flag bit: (a7)+ +set mda7_flg, 0x08 # flag bit: -(a7) +set fmovm_flg, 0x40 # flag bit: fmovm instruction +set immed_flg, 0x80 # flag bit: & + +set ftrapcc_bit, 0x0 +set fbsun_bit, 0x1 +set mia7_bit, 0x2 +set mda7_bit, 0x3 +set immed_bit, 0x7 + +################################## +# TRANSCENDENTAL "LAST-OP" FLAGS # +################################## +set FMUL_OP, 0x0 # fmul instr performed last +set FDIV_OP, 0x1 # fdiv performed last +set FADD_OP, 0x2 # fadd performed last +set FMOV_OP, 0x3 # fmov performed last + +############# +# CONSTANTS # +############# +T1: long 0x40C62D38,0xD3D64634 # 16381 LOG2 LEAD +T2: long 0x3D6F90AE,0xB1E75CC7 # 16381 LOG2 TRAIL + +PI: long 0x40000000,0xC90FDAA2,0x2168C235,0x00000000 +PIBY2: long 0x3FFF0000,0xC90FDAA2,0x2168C235,0x00000000 + +TWOBYPI: + long 0x3FE45F30,0x6DC9C883 + +######################################################################### +# MONADIC TEMPLATE # +######################################################################### + global _fsins_ +_fsins_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.s 0x8(%a6),%fp0 # load sgl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L0_2s + bsr.l ssin # operand is a NORM + bra.b _L0_6s +_L0_2s: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L0_3s # no + bsr.l src_zero # yes + bra.b _L0_6s +_L0_3s: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L0_4s # no + bsr.l t_operr # yes + bra.b _L0_6s +_L0_4s: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L0_5s # no + bsr.l src_qnan # yes + bra.b _L0_6s +_L0_5s: + bsr.l ssind # operand is a DENORM +_L0_6s: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fsind_ +_fsind_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.d 0x8(%a6),%fp0 # load dbl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + mov.b %d1,STAG(%a6) + tst.b %d1 + bne.b _L0_2d + bsr.l ssin # operand is a NORM + bra.b _L0_6d +_L0_2d: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L0_3d # no + bsr.l src_zero # yes + bra.b _L0_6d +_L0_3d: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L0_4d # no + bsr.l t_operr # yes + bra.b _L0_6d +_L0_4d: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L0_5d # no + bsr.l src_qnan # yes + bra.b _L0_6d +_L0_5d: + bsr.l ssind # operand is a DENORM +_L0_6d: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fsinx_ +_fsinx_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + lea FP_SRC(%a6),%a0 + mov.l 0x8+0x0(%a6),0x0(%a0) # load ext input + mov.l 0x8+0x4(%a6),0x4(%a0) + mov.l 0x8+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L0_2x + bsr.l ssin # operand is a NORM + bra.b _L0_6x +_L0_2x: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L0_3x # no + bsr.l src_zero # yes + bra.b _L0_6x +_L0_3x: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L0_4x # no + bsr.l t_operr # yes + bra.b _L0_6x +_L0_4x: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L0_5x # no + bsr.l src_qnan # yes + bra.b _L0_6x +_L0_5x: + bsr.l ssind # operand is a DENORM +_L0_6x: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + +######################################################################### +# MONADIC TEMPLATE # +######################################################################### + global _fcoss_ +_fcoss_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.s 0x8(%a6),%fp0 # load sgl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L1_2s + bsr.l scos # operand is a NORM + bra.b _L1_6s +_L1_2s: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L1_3s # no + bsr.l ld_pone # yes + bra.b _L1_6s +_L1_3s: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L1_4s # no + bsr.l t_operr # yes + bra.b _L1_6s +_L1_4s: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L1_5s # no + bsr.l src_qnan # yes + bra.b _L1_6s +_L1_5s: + bsr.l scosd # operand is a DENORM +_L1_6s: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fcosd_ +_fcosd_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.d 0x8(%a6),%fp0 # load dbl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + mov.b %d1,STAG(%a6) + tst.b %d1 + bne.b _L1_2d + bsr.l scos # operand is a NORM + bra.b _L1_6d +_L1_2d: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L1_3d # no + bsr.l ld_pone # yes + bra.b _L1_6d +_L1_3d: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L1_4d # no + bsr.l t_operr # yes + bra.b _L1_6d +_L1_4d: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L1_5d # no + bsr.l src_qnan # yes + bra.b _L1_6d +_L1_5d: + bsr.l scosd # operand is a DENORM +_L1_6d: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fcosx_ +_fcosx_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + lea FP_SRC(%a6),%a0 + mov.l 0x8+0x0(%a6),0x0(%a0) # load ext input + mov.l 0x8+0x4(%a6),0x4(%a0) + mov.l 0x8+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L1_2x + bsr.l scos # operand is a NORM + bra.b _L1_6x +_L1_2x: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L1_3x # no + bsr.l ld_pone # yes + bra.b _L1_6x +_L1_3x: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L1_4x # no + bsr.l t_operr # yes + bra.b _L1_6x +_L1_4x: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L1_5x # no + bsr.l src_qnan # yes + bra.b _L1_6x +_L1_5x: + bsr.l scosd # operand is a DENORM +_L1_6x: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + +######################################################################### +# MONADIC TEMPLATE # +######################################################################### + global _fsinhs_ +_fsinhs_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.s 0x8(%a6),%fp0 # load sgl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L2_2s + bsr.l ssinh # operand is a NORM + bra.b _L2_6s +_L2_2s: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L2_3s # no + bsr.l src_zero # yes + bra.b _L2_6s +_L2_3s: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L2_4s # no + bsr.l src_inf # yes + bra.b _L2_6s +_L2_4s: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L2_5s # no + bsr.l src_qnan # yes + bra.b _L2_6s +_L2_5s: + bsr.l ssinhd # operand is a DENORM +_L2_6s: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fsinhd_ +_fsinhd_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.d 0x8(%a6),%fp0 # load dbl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + mov.b %d1,STAG(%a6) + tst.b %d1 + bne.b _L2_2d + bsr.l ssinh # operand is a NORM + bra.b _L2_6d +_L2_2d: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L2_3d # no + bsr.l src_zero # yes + bra.b _L2_6d +_L2_3d: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L2_4d # no + bsr.l src_inf # yes + bra.b _L2_6d +_L2_4d: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L2_5d # no + bsr.l src_qnan # yes + bra.b _L2_6d +_L2_5d: + bsr.l ssinhd # operand is a DENORM +_L2_6d: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fsinhx_ +_fsinhx_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + lea FP_SRC(%a6),%a0 + mov.l 0x8+0x0(%a6),0x0(%a0) # load ext input + mov.l 0x8+0x4(%a6),0x4(%a0) + mov.l 0x8+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L2_2x + bsr.l ssinh # operand is a NORM + bra.b _L2_6x +_L2_2x: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L2_3x # no + bsr.l src_zero # yes + bra.b _L2_6x +_L2_3x: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L2_4x # no + bsr.l src_inf # yes + bra.b _L2_6x +_L2_4x: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L2_5x # no + bsr.l src_qnan # yes + bra.b _L2_6x +_L2_5x: + bsr.l ssinhd # operand is a DENORM +_L2_6x: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + +######################################################################### +# MONADIC TEMPLATE # +######################################################################### + global _flognp1s_ +_flognp1s_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.s 0x8(%a6),%fp0 # load sgl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L3_2s + bsr.l slognp1 # operand is a NORM + bra.b _L3_6s +_L3_2s: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L3_3s # no + bsr.l src_zero # yes + bra.b _L3_6s +_L3_3s: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L3_4s # no + bsr.l sopr_inf # yes + bra.b _L3_6s +_L3_4s: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L3_5s # no + bsr.l src_qnan # yes + bra.b _L3_6s +_L3_5s: + bsr.l slognp1d # operand is a DENORM +_L3_6s: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _flognp1d_ +_flognp1d_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.d 0x8(%a6),%fp0 # load dbl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + mov.b %d1,STAG(%a6) + tst.b %d1 + bne.b _L3_2d + bsr.l slognp1 # operand is a NORM + bra.b _L3_6d +_L3_2d: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L3_3d # no + bsr.l src_zero # yes + bra.b _L3_6d +_L3_3d: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L3_4d # no + bsr.l sopr_inf # yes + bra.b _L3_6d +_L3_4d: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L3_5d # no + bsr.l src_qnan # yes + bra.b _L3_6d +_L3_5d: + bsr.l slognp1d # operand is a DENORM +_L3_6d: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _flognp1x_ +_flognp1x_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + lea FP_SRC(%a6),%a0 + mov.l 0x8+0x0(%a6),0x0(%a0) # load ext input + mov.l 0x8+0x4(%a6),0x4(%a0) + mov.l 0x8+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L3_2x + bsr.l slognp1 # operand is a NORM + bra.b _L3_6x +_L3_2x: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L3_3x # no + bsr.l src_zero # yes + bra.b _L3_6x +_L3_3x: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L3_4x # no + bsr.l sopr_inf # yes + bra.b _L3_6x +_L3_4x: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L3_5x # no + bsr.l src_qnan # yes + bra.b _L3_6x +_L3_5x: + bsr.l slognp1d # operand is a DENORM +_L3_6x: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + +######################################################################### +# MONADIC TEMPLATE # +######################################################################### + global _fetoxm1s_ +_fetoxm1s_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.s 0x8(%a6),%fp0 # load sgl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L4_2s + bsr.l setoxm1 # operand is a NORM + bra.b _L4_6s +_L4_2s: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L4_3s # no + bsr.l src_zero # yes + bra.b _L4_6s +_L4_3s: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L4_4s # no + bsr.l setoxm1i # yes + bra.b _L4_6s +_L4_4s: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L4_5s # no + bsr.l src_qnan # yes + bra.b _L4_6s +_L4_5s: + bsr.l setoxm1d # operand is a DENORM +_L4_6s: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fetoxm1d_ +_fetoxm1d_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.d 0x8(%a6),%fp0 # load dbl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + mov.b %d1,STAG(%a6) + tst.b %d1 + bne.b _L4_2d + bsr.l setoxm1 # operand is a NORM + bra.b _L4_6d +_L4_2d: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L4_3d # no + bsr.l src_zero # yes + bra.b _L4_6d +_L4_3d: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L4_4d # no + bsr.l setoxm1i # yes + bra.b _L4_6d +_L4_4d: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L4_5d # no + bsr.l src_qnan # yes + bra.b _L4_6d +_L4_5d: + bsr.l setoxm1d # operand is a DENORM +_L4_6d: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fetoxm1x_ +_fetoxm1x_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + lea FP_SRC(%a6),%a0 + mov.l 0x8+0x0(%a6),0x0(%a0) # load ext input + mov.l 0x8+0x4(%a6),0x4(%a0) + mov.l 0x8+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L4_2x + bsr.l setoxm1 # operand is a NORM + bra.b _L4_6x +_L4_2x: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L4_3x # no + bsr.l src_zero # yes + bra.b _L4_6x +_L4_3x: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L4_4x # no + bsr.l setoxm1i # yes + bra.b _L4_6x +_L4_4x: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L4_5x # no + bsr.l src_qnan # yes + bra.b _L4_6x +_L4_5x: + bsr.l setoxm1d # operand is a DENORM +_L4_6x: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + +######################################################################### +# MONADIC TEMPLATE # +######################################################################### + global _ftanhs_ +_ftanhs_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.s 0x8(%a6),%fp0 # load sgl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L5_2s + bsr.l stanh # operand is a NORM + bra.b _L5_6s +_L5_2s: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L5_3s # no + bsr.l src_zero # yes + bra.b _L5_6s +_L5_3s: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L5_4s # no + bsr.l src_one # yes + bra.b _L5_6s +_L5_4s: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L5_5s # no + bsr.l src_qnan # yes + bra.b _L5_6s +_L5_5s: + bsr.l stanhd # operand is a DENORM +_L5_6s: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _ftanhd_ +_ftanhd_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.d 0x8(%a6),%fp0 # load dbl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + mov.b %d1,STAG(%a6) + tst.b %d1 + bne.b _L5_2d + bsr.l stanh # operand is a NORM + bra.b _L5_6d +_L5_2d: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L5_3d # no + bsr.l src_zero # yes + bra.b _L5_6d +_L5_3d: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L5_4d # no + bsr.l src_one # yes + bra.b _L5_6d +_L5_4d: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L5_5d # no + bsr.l src_qnan # yes + bra.b _L5_6d +_L5_5d: + bsr.l stanhd # operand is a DENORM +_L5_6d: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _ftanhx_ +_ftanhx_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + lea FP_SRC(%a6),%a0 + mov.l 0x8+0x0(%a6),0x0(%a0) # load ext input + mov.l 0x8+0x4(%a6),0x4(%a0) + mov.l 0x8+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L5_2x + bsr.l stanh # operand is a NORM + bra.b _L5_6x +_L5_2x: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L5_3x # no + bsr.l src_zero # yes + bra.b _L5_6x +_L5_3x: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L5_4x # no + bsr.l src_one # yes + bra.b _L5_6x +_L5_4x: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L5_5x # no + bsr.l src_qnan # yes + bra.b _L5_6x +_L5_5x: + bsr.l stanhd # operand is a DENORM +_L5_6x: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + +######################################################################### +# MONADIC TEMPLATE # +######################################################################### + global _fatans_ +_fatans_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.s 0x8(%a6),%fp0 # load sgl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L6_2s + bsr.l satan # operand is a NORM + bra.b _L6_6s +_L6_2s: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L6_3s # no + bsr.l src_zero # yes + bra.b _L6_6s +_L6_3s: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L6_4s # no + bsr.l spi_2 # yes + bra.b _L6_6s +_L6_4s: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L6_5s # no + bsr.l src_qnan # yes + bra.b _L6_6s +_L6_5s: + bsr.l satand # operand is a DENORM +_L6_6s: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fatand_ +_fatand_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.d 0x8(%a6),%fp0 # load dbl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + mov.b %d1,STAG(%a6) + tst.b %d1 + bne.b _L6_2d + bsr.l satan # operand is a NORM + bra.b _L6_6d +_L6_2d: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L6_3d # no + bsr.l src_zero # yes + bra.b _L6_6d +_L6_3d: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L6_4d # no + bsr.l spi_2 # yes + bra.b _L6_6d +_L6_4d: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L6_5d # no + bsr.l src_qnan # yes + bra.b _L6_6d +_L6_5d: + bsr.l satand # operand is a DENORM +_L6_6d: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fatanx_ +_fatanx_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + lea FP_SRC(%a6),%a0 + mov.l 0x8+0x0(%a6),0x0(%a0) # load ext input + mov.l 0x8+0x4(%a6),0x4(%a0) + mov.l 0x8+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L6_2x + bsr.l satan # operand is a NORM + bra.b _L6_6x +_L6_2x: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L6_3x # no + bsr.l src_zero # yes + bra.b _L6_6x +_L6_3x: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L6_4x # no + bsr.l spi_2 # yes + bra.b _L6_6x +_L6_4x: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L6_5x # no + bsr.l src_qnan # yes + bra.b _L6_6x +_L6_5x: + bsr.l satand # operand is a DENORM +_L6_6x: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + +######################################################################### +# MONADIC TEMPLATE # +######################################################################### + global _fasins_ +_fasins_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.s 0x8(%a6),%fp0 # load sgl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L7_2s + bsr.l sasin # operand is a NORM + bra.b _L7_6s +_L7_2s: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L7_3s # no + bsr.l src_zero # yes + bra.b _L7_6s +_L7_3s: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L7_4s # no + bsr.l t_operr # yes + bra.b _L7_6s +_L7_4s: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L7_5s # no + bsr.l src_qnan # yes + bra.b _L7_6s +_L7_5s: + bsr.l sasind # operand is a DENORM +_L7_6s: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fasind_ +_fasind_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.d 0x8(%a6),%fp0 # load dbl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + mov.b %d1,STAG(%a6) + tst.b %d1 + bne.b _L7_2d + bsr.l sasin # operand is a NORM + bra.b _L7_6d +_L7_2d: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L7_3d # no + bsr.l src_zero # yes + bra.b _L7_6d +_L7_3d: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L7_4d # no + bsr.l t_operr # yes + bra.b _L7_6d +_L7_4d: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L7_5d # no + bsr.l src_qnan # yes + bra.b _L7_6d +_L7_5d: + bsr.l sasind # operand is a DENORM +_L7_6d: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fasinx_ +_fasinx_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + lea FP_SRC(%a6),%a0 + mov.l 0x8+0x0(%a6),0x0(%a0) # load ext input + mov.l 0x8+0x4(%a6),0x4(%a0) + mov.l 0x8+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L7_2x + bsr.l sasin # operand is a NORM + bra.b _L7_6x +_L7_2x: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L7_3x # no + bsr.l src_zero # yes + bra.b _L7_6x +_L7_3x: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L7_4x # no + bsr.l t_operr # yes + bra.b _L7_6x +_L7_4x: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L7_5x # no + bsr.l src_qnan # yes + bra.b _L7_6x +_L7_5x: + bsr.l sasind # operand is a DENORM +_L7_6x: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + +######################################################################### +# MONADIC TEMPLATE # +######################################################################### + global _fatanhs_ +_fatanhs_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.s 0x8(%a6),%fp0 # load sgl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L8_2s + bsr.l satanh # operand is a NORM + bra.b _L8_6s +_L8_2s: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L8_3s # no + bsr.l src_zero # yes + bra.b _L8_6s +_L8_3s: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L8_4s # no + bsr.l t_operr # yes + bra.b _L8_6s +_L8_4s: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L8_5s # no + bsr.l src_qnan # yes + bra.b _L8_6s +_L8_5s: + bsr.l satanhd # operand is a DENORM +_L8_6s: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fatanhd_ +_fatanhd_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.d 0x8(%a6),%fp0 # load dbl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + mov.b %d1,STAG(%a6) + tst.b %d1 + bne.b _L8_2d + bsr.l satanh # operand is a NORM + bra.b _L8_6d +_L8_2d: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L8_3d # no + bsr.l src_zero # yes + bra.b _L8_6d +_L8_3d: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L8_4d # no + bsr.l t_operr # yes + bra.b _L8_6d +_L8_4d: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L8_5d # no + bsr.l src_qnan # yes + bra.b _L8_6d +_L8_5d: + bsr.l satanhd # operand is a DENORM +_L8_6d: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fatanhx_ +_fatanhx_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + lea FP_SRC(%a6),%a0 + mov.l 0x8+0x0(%a6),0x0(%a0) # load ext input + mov.l 0x8+0x4(%a6),0x4(%a0) + mov.l 0x8+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L8_2x + bsr.l satanh # operand is a NORM + bra.b _L8_6x +_L8_2x: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L8_3x # no + bsr.l src_zero # yes + bra.b _L8_6x +_L8_3x: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L8_4x # no + bsr.l t_operr # yes + bra.b _L8_6x +_L8_4x: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L8_5x # no + bsr.l src_qnan # yes + bra.b _L8_6x +_L8_5x: + bsr.l satanhd # operand is a DENORM +_L8_6x: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + +######################################################################### +# MONADIC TEMPLATE # +######################################################################### + global _ftans_ +_ftans_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.s 0x8(%a6),%fp0 # load sgl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L9_2s + bsr.l stan # operand is a NORM + bra.b _L9_6s +_L9_2s: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L9_3s # no + bsr.l src_zero # yes + bra.b _L9_6s +_L9_3s: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L9_4s # no + bsr.l t_operr # yes + bra.b _L9_6s +_L9_4s: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L9_5s # no + bsr.l src_qnan # yes + bra.b _L9_6s +_L9_5s: + bsr.l stand # operand is a DENORM +_L9_6s: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _ftand_ +_ftand_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.d 0x8(%a6),%fp0 # load dbl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + mov.b %d1,STAG(%a6) + tst.b %d1 + bne.b _L9_2d + bsr.l stan # operand is a NORM + bra.b _L9_6d +_L9_2d: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L9_3d # no + bsr.l src_zero # yes + bra.b _L9_6d +_L9_3d: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L9_4d # no + bsr.l t_operr # yes + bra.b _L9_6d +_L9_4d: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L9_5d # no + bsr.l src_qnan # yes + bra.b _L9_6d +_L9_5d: + bsr.l stand # operand is a DENORM +_L9_6d: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _ftanx_ +_ftanx_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + lea FP_SRC(%a6),%a0 + mov.l 0x8+0x0(%a6),0x0(%a0) # load ext input + mov.l 0x8+0x4(%a6),0x4(%a0) + mov.l 0x8+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L9_2x + bsr.l stan # operand is a NORM + bra.b _L9_6x +_L9_2x: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L9_3x # no + bsr.l src_zero # yes + bra.b _L9_6x +_L9_3x: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L9_4x # no + bsr.l t_operr # yes + bra.b _L9_6x +_L9_4x: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L9_5x # no + bsr.l src_qnan # yes + bra.b _L9_6x +_L9_5x: + bsr.l stand # operand is a DENORM +_L9_6x: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + +######################################################################### +# MONADIC TEMPLATE # +######################################################################### + global _fetoxs_ +_fetoxs_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.s 0x8(%a6),%fp0 # load sgl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L10_2s + bsr.l setox # operand is a NORM + bra.b _L10_6s +_L10_2s: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L10_3s # no + bsr.l ld_pone # yes + bra.b _L10_6s +_L10_3s: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L10_4s # no + bsr.l szr_inf # yes + bra.b _L10_6s +_L10_4s: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L10_5s # no + bsr.l src_qnan # yes + bra.b _L10_6s +_L10_5s: + bsr.l setoxd # operand is a DENORM +_L10_6s: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fetoxd_ +_fetoxd_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.d 0x8(%a6),%fp0 # load dbl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + mov.b %d1,STAG(%a6) + tst.b %d1 + bne.b _L10_2d + bsr.l setox # operand is a NORM + bra.b _L10_6d +_L10_2d: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L10_3d # no + bsr.l ld_pone # yes + bra.b _L10_6d +_L10_3d: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L10_4d # no + bsr.l szr_inf # yes + bra.b _L10_6d +_L10_4d: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L10_5d # no + bsr.l src_qnan # yes + bra.b _L10_6d +_L10_5d: + bsr.l setoxd # operand is a DENORM +_L10_6d: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fetoxx_ +_fetoxx_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + lea FP_SRC(%a6),%a0 + mov.l 0x8+0x0(%a6),0x0(%a0) # load ext input + mov.l 0x8+0x4(%a6),0x4(%a0) + mov.l 0x8+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L10_2x + bsr.l setox # operand is a NORM + bra.b _L10_6x +_L10_2x: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L10_3x # no + bsr.l ld_pone # yes + bra.b _L10_6x +_L10_3x: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L10_4x # no + bsr.l szr_inf # yes + bra.b _L10_6x +_L10_4x: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L10_5x # no + bsr.l src_qnan # yes + bra.b _L10_6x +_L10_5x: + bsr.l setoxd # operand is a DENORM +_L10_6x: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + +######################################################################### +# MONADIC TEMPLATE # +######################################################################### + global _ftwotoxs_ +_ftwotoxs_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.s 0x8(%a6),%fp0 # load sgl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L11_2s + bsr.l stwotox # operand is a NORM + bra.b _L11_6s +_L11_2s: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L11_3s # no + bsr.l ld_pone # yes + bra.b _L11_6s +_L11_3s: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L11_4s # no + bsr.l szr_inf # yes + bra.b _L11_6s +_L11_4s: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L11_5s # no + bsr.l src_qnan # yes + bra.b _L11_6s +_L11_5s: + bsr.l stwotoxd # operand is a DENORM +_L11_6s: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _ftwotoxd_ +_ftwotoxd_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.d 0x8(%a6),%fp0 # load dbl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + mov.b %d1,STAG(%a6) + tst.b %d1 + bne.b _L11_2d + bsr.l stwotox # operand is a NORM + bra.b _L11_6d +_L11_2d: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L11_3d # no + bsr.l ld_pone # yes + bra.b _L11_6d +_L11_3d: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L11_4d # no + bsr.l szr_inf # yes + bra.b _L11_6d +_L11_4d: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L11_5d # no + bsr.l src_qnan # yes + bra.b _L11_6d +_L11_5d: + bsr.l stwotoxd # operand is a DENORM +_L11_6d: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _ftwotoxx_ +_ftwotoxx_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + lea FP_SRC(%a6),%a0 + mov.l 0x8+0x0(%a6),0x0(%a0) # load ext input + mov.l 0x8+0x4(%a6),0x4(%a0) + mov.l 0x8+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L11_2x + bsr.l stwotox # operand is a NORM + bra.b _L11_6x +_L11_2x: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L11_3x # no + bsr.l ld_pone # yes + bra.b _L11_6x +_L11_3x: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L11_4x # no + bsr.l szr_inf # yes + bra.b _L11_6x +_L11_4x: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L11_5x # no + bsr.l src_qnan # yes + bra.b _L11_6x +_L11_5x: + bsr.l stwotoxd # operand is a DENORM +_L11_6x: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + +######################################################################### +# MONADIC TEMPLATE # +######################################################################### + global _ftentoxs_ +_ftentoxs_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.s 0x8(%a6),%fp0 # load sgl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L12_2s + bsr.l stentox # operand is a NORM + bra.b _L12_6s +_L12_2s: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L12_3s # no + bsr.l ld_pone # yes + bra.b _L12_6s +_L12_3s: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L12_4s # no + bsr.l szr_inf # yes + bra.b _L12_6s +_L12_4s: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L12_5s # no + bsr.l src_qnan # yes + bra.b _L12_6s +_L12_5s: + bsr.l stentoxd # operand is a DENORM +_L12_6s: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _ftentoxd_ +_ftentoxd_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.d 0x8(%a6),%fp0 # load dbl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + mov.b %d1,STAG(%a6) + tst.b %d1 + bne.b _L12_2d + bsr.l stentox # operand is a NORM + bra.b _L12_6d +_L12_2d: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L12_3d # no + bsr.l ld_pone # yes + bra.b _L12_6d +_L12_3d: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L12_4d # no + bsr.l szr_inf # yes + bra.b _L12_6d +_L12_4d: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L12_5d # no + bsr.l src_qnan # yes + bra.b _L12_6d +_L12_5d: + bsr.l stentoxd # operand is a DENORM +_L12_6d: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _ftentoxx_ +_ftentoxx_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + lea FP_SRC(%a6),%a0 + mov.l 0x8+0x0(%a6),0x0(%a0) # load ext input + mov.l 0x8+0x4(%a6),0x4(%a0) + mov.l 0x8+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L12_2x + bsr.l stentox # operand is a NORM + bra.b _L12_6x +_L12_2x: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L12_3x # no + bsr.l ld_pone # yes + bra.b _L12_6x +_L12_3x: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L12_4x # no + bsr.l szr_inf # yes + bra.b _L12_6x +_L12_4x: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L12_5x # no + bsr.l src_qnan # yes + bra.b _L12_6x +_L12_5x: + bsr.l stentoxd # operand is a DENORM +_L12_6x: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + +######################################################################### +# MONADIC TEMPLATE # +######################################################################### + global _flogns_ +_flogns_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.s 0x8(%a6),%fp0 # load sgl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L13_2s + bsr.l slogn # operand is a NORM + bra.b _L13_6s +_L13_2s: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L13_3s # no + bsr.l t_dz2 # yes + bra.b _L13_6s +_L13_3s: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L13_4s # no + bsr.l sopr_inf # yes + bra.b _L13_6s +_L13_4s: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L13_5s # no + bsr.l src_qnan # yes + bra.b _L13_6s +_L13_5s: + bsr.l slognd # operand is a DENORM +_L13_6s: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _flognd_ +_flognd_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.d 0x8(%a6),%fp0 # load dbl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + mov.b %d1,STAG(%a6) + tst.b %d1 + bne.b _L13_2d + bsr.l slogn # operand is a NORM + bra.b _L13_6d +_L13_2d: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L13_3d # no + bsr.l t_dz2 # yes + bra.b _L13_6d +_L13_3d: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L13_4d # no + bsr.l sopr_inf # yes + bra.b _L13_6d +_L13_4d: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L13_5d # no + bsr.l src_qnan # yes + bra.b _L13_6d +_L13_5d: + bsr.l slognd # operand is a DENORM +_L13_6d: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _flognx_ +_flognx_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + lea FP_SRC(%a6),%a0 + mov.l 0x8+0x0(%a6),0x0(%a0) # load ext input + mov.l 0x8+0x4(%a6),0x4(%a0) + mov.l 0x8+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L13_2x + bsr.l slogn # operand is a NORM + bra.b _L13_6x +_L13_2x: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L13_3x # no + bsr.l t_dz2 # yes + bra.b _L13_6x +_L13_3x: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L13_4x # no + bsr.l sopr_inf # yes + bra.b _L13_6x +_L13_4x: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L13_5x # no + bsr.l src_qnan # yes + bra.b _L13_6x +_L13_5x: + bsr.l slognd # operand is a DENORM +_L13_6x: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + +######################################################################### +# MONADIC TEMPLATE # +######################################################################### + global _flog10s_ +_flog10s_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.s 0x8(%a6),%fp0 # load sgl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L14_2s + bsr.l slog10 # operand is a NORM + bra.b _L14_6s +_L14_2s: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L14_3s # no + bsr.l t_dz2 # yes + bra.b _L14_6s +_L14_3s: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L14_4s # no + bsr.l sopr_inf # yes + bra.b _L14_6s +_L14_4s: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L14_5s # no + bsr.l src_qnan # yes + bra.b _L14_6s +_L14_5s: + bsr.l slog10d # operand is a DENORM +_L14_6s: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _flog10d_ +_flog10d_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.d 0x8(%a6),%fp0 # load dbl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + mov.b %d1,STAG(%a6) + tst.b %d1 + bne.b _L14_2d + bsr.l slog10 # operand is a NORM + bra.b _L14_6d +_L14_2d: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L14_3d # no + bsr.l t_dz2 # yes + bra.b _L14_6d +_L14_3d: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L14_4d # no + bsr.l sopr_inf # yes + bra.b _L14_6d +_L14_4d: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L14_5d # no + bsr.l src_qnan # yes + bra.b _L14_6d +_L14_5d: + bsr.l slog10d # operand is a DENORM +_L14_6d: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _flog10x_ +_flog10x_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + lea FP_SRC(%a6),%a0 + mov.l 0x8+0x0(%a6),0x0(%a0) # load ext input + mov.l 0x8+0x4(%a6),0x4(%a0) + mov.l 0x8+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L14_2x + bsr.l slog10 # operand is a NORM + bra.b _L14_6x +_L14_2x: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L14_3x # no + bsr.l t_dz2 # yes + bra.b _L14_6x +_L14_3x: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L14_4x # no + bsr.l sopr_inf # yes + bra.b _L14_6x +_L14_4x: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L14_5x # no + bsr.l src_qnan # yes + bra.b _L14_6x +_L14_5x: + bsr.l slog10d # operand is a DENORM +_L14_6x: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + +######################################################################### +# MONADIC TEMPLATE # +######################################################################### + global _flog2s_ +_flog2s_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.s 0x8(%a6),%fp0 # load sgl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L15_2s + bsr.l slog2 # operand is a NORM + bra.b _L15_6s +_L15_2s: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L15_3s # no + bsr.l t_dz2 # yes + bra.b _L15_6s +_L15_3s: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L15_4s # no + bsr.l sopr_inf # yes + bra.b _L15_6s +_L15_4s: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L15_5s # no + bsr.l src_qnan # yes + bra.b _L15_6s +_L15_5s: + bsr.l slog2d # operand is a DENORM +_L15_6s: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _flog2d_ +_flog2d_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.d 0x8(%a6),%fp0 # load dbl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + mov.b %d1,STAG(%a6) + tst.b %d1 + bne.b _L15_2d + bsr.l slog2 # operand is a NORM + bra.b _L15_6d +_L15_2d: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L15_3d # no + bsr.l t_dz2 # yes + bra.b _L15_6d +_L15_3d: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L15_4d # no + bsr.l sopr_inf # yes + bra.b _L15_6d +_L15_4d: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L15_5d # no + bsr.l src_qnan # yes + bra.b _L15_6d +_L15_5d: + bsr.l slog2d # operand is a DENORM +_L15_6d: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _flog2x_ +_flog2x_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + lea FP_SRC(%a6),%a0 + mov.l 0x8+0x0(%a6),0x0(%a0) # load ext input + mov.l 0x8+0x4(%a6),0x4(%a0) + mov.l 0x8+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L15_2x + bsr.l slog2 # operand is a NORM + bra.b _L15_6x +_L15_2x: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L15_3x # no + bsr.l t_dz2 # yes + bra.b _L15_6x +_L15_3x: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L15_4x # no + bsr.l sopr_inf # yes + bra.b _L15_6x +_L15_4x: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L15_5x # no + bsr.l src_qnan # yes + bra.b _L15_6x +_L15_5x: + bsr.l slog2d # operand is a DENORM +_L15_6x: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + +######################################################################### +# MONADIC TEMPLATE # +######################################################################### + global _fcoshs_ +_fcoshs_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.s 0x8(%a6),%fp0 # load sgl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L16_2s + bsr.l scosh # operand is a NORM + bra.b _L16_6s +_L16_2s: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L16_3s # no + bsr.l ld_pone # yes + bra.b _L16_6s +_L16_3s: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L16_4s # no + bsr.l ld_pinf # yes + bra.b _L16_6s +_L16_4s: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L16_5s # no + bsr.l src_qnan # yes + bra.b _L16_6s +_L16_5s: + bsr.l scoshd # operand is a DENORM +_L16_6s: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fcoshd_ +_fcoshd_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.d 0x8(%a6),%fp0 # load dbl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + mov.b %d1,STAG(%a6) + tst.b %d1 + bne.b _L16_2d + bsr.l scosh # operand is a NORM + bra.b _L16_6d +_L16_2d: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L16_3d # no + bsr.l ld_pone # yes + bra.b _L16_6d +_L16_3d: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L16_4d # no + bsr.l ld_pinf # yes + bra.b _L16_6d +_L16_4d: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L16_5d # no + bsr.l src_qnan # yes + bra.b _L16_6d +_L16_5d: + bsr.l scoshd # operand is a DENORM +_L16_6d: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fcoshx_ +_fcoshx_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + lea FP_SRC(%a6),%a0 + mov.l 0x8+0x0(%a6),0x0(%a0) # load ext input + mov.l 0x8+0x4(%a6),0x4(%a0) + mov.l 0x8+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L16_2x + bsr.l scosh # operand is a NORM + bra.b _L16_6x +_L16_2x: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L16_3x # no + bsr.l ld_pone # yes + bra.b _L16_6x +_L16_3x: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L16_4x # no + bsr.l ld_pinf # yes + bra.b _L16_6x +_L16_4x: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L16_5x # no + bsr.l src_qnan # yes + bra.b _L16_6x +_L16_5x: + bsr.l scoshd # operand is a DENORM +_L16_6x: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + +######################################################################### +# MONADIC TEMPLATE # +######################################################################### + global _facoss_ +_facoss_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.s 0x8(%a6),%fp0 # load sgl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L17_2s + bsr.l sacos # operand is a NORM + bra.b _L17_6s +_L17_2s: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L17_3s # no + bsr.l ld_ppi2 # yes + bra.b _L17_6s +_L17_3s: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L17_4s # no + bsr.l t_operr # yes + bra.b _L17_6s +_L17_4s: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L17_5s # no + bsr.l src_qnan # yes + bra.b _L17_6s +_L17_5s: + bsr.l sacosd # operand is a DENORM +_L17_6s: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _facosd_ +_facosd_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.d 0x8(%a6),%fp0 # load dbl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + mov.b %d1,STAG(%a6) + tst.b %d1 + bne.b _L17_2d + bsr.l sacos # operand is a NORM + bra.b _L17_6d +_L17_2d: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L17_3d # no + bsr.l ld_ppi2 # yes + bra.b _L17_6d +_L17_3d: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L17_4d # no + bsr.l t_operr # yes + bra.b _L17_6d +_L17_4d: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L17_5d # no + bsr.l src_qnan # yes + bra.b _L17_6d +_L17_5d: + bsr.l sacosd # operand is a DENORM +_L17_6d: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _facosx_ +_facosx_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + lea FP_SRC(%a6),%a0 + mov.l 0x8+0x0(%a6),0x0(%a0) # load ext input + mov.l 0x8+0x4(%a6),0x4(%a0) + mov.l 0x8+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L17_2x + bsr.l sacos # operand is a NORM + bra.b _L17_6x +_L17_2x: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L17_3x # no + bsr.l ld_ppi2 # yes + bra.b _L17_6x +_L17_3x: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L17_4x # no + bsr.l t_operr # yes + bra.b _L17_6x +_L17_4x: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L17_5x # no + bsr.l src_qnan # yes + bra.b _L17_6x +_L17_5x: + bsr.l sacosd # operand is a DENORM +_L17_6x: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + +######################################################################### +# MONADIC TEMPLATE # +######################################################################### + global _fgetexps_ +_fgetexps_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.s 0x8(%a6),%fp0 # load sgl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L18_2s + bsr.l sgetexp # operand is a NORM + bra.b _L18_6s +_L18_2s: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L18_3s # no + bsr.l src_zero # yes + bra.b _L18_6s +_L18_3s: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L18_4s # no + bsr.l t_operr # yes + bra.b _L18_6s +_L18_4s: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L18_5s # no + bsr.l src_qnan # yes + bra.b _L18_6s +_L18_5s: + bsr.l sgetexpd # operand is a DENORM +_L18_6s: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fgetexpd_ +_fgetexpd_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.d 0x8(%a6),%fp0 # load dbl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + mov.b %d1,STAG(%a6) + tst.b %d1 + bne.b _L18_2d + bsr.l sgetexp # operand is a NORM + bra.b _L18_6d +_L18_2d: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L18_3d # no + bsr.l src_zero # yes + bra.b _L18_6d +_L18_3d: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L18_4d # no + bsr.l t_operr # yes + bra.b _L18_6d +_L18_4d: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L18_5d # no + bsr.l src_qnan # yes + bra.b _L18_6d +_L18_5d: + bsr.l sgetexpd # operand is a DENORM +_L18_6d: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fgetexpx_ +_fgetexpx_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + lea FP_SRC(%a6),%a0 + mov.l 0x8+0x0(%a6),0x0(%a0) # load ext input + mov.l 0x8+0x4(%a6),0x4(%a0) + mov.l 0x8+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L18_2x + bsr.l sgetexp # operand is a NORM + bra.b _L18_6x +_L18_2x: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L18_3x # no + bsr.l src_zero # yes + bra.b _L18_6x +_L18_3x: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L18_4x # no + bsr.l t_operr # yes + bra.b _L18_6x +_L18_4x: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L18_5x # no + bsr.l src_qnan # yes + bra.b _L18_6x +_L18_5x: + bsr.l sgetexpd # operand is a DENORM +_L18_6x: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + +######################################################################### +# MONADIC TEMPLATE # +######################################################################### + global _fgetmans_ +_fgetmans_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.s 0x8(%a6),%fp0 # load sgl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L19_2s + bsr.l sgetman # operand is a NORM + bra.b _L19_6s +_L19_2s: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L19_3s # no + bsr.l src_zero # yes + bra.b _L19_6s +_L19_3s: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L19_4s # no + bsr.l t_operr # yes + bra.b _L19_6s +_L19_4s: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L19_5s # no + bsr.l src_qnan # yes + bra.b _L19_6s +_L19_5s: + bsr.l sgetmand # operand is a DENORM +_L19_6s: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fgetmand_ +_fgetmand_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.d 0x8(%a6),%fp0 # load dbl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + mov.b %d1,STAG(%a6) + tst.b %d1 + bne.b _L19_2d + bsr.l sgetman # operand is a NORM + bra.b _L19_6d +_L19_2d: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L19_3d # no + bsr.l src_zero # yes + bra.b _L19_6d +_L19_3d: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L19_4d # no + bsr.l t_operr # yes + bra.b _L19_6d +_L19_4d: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L19_5d # no + bsr.l src_qnan # yes + bra.b _L19_6d +_L19_5d: + bsr.l sgetmand # operand is a DENORM +_L19_6d: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fgetmanx_ +_fgetmanx_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + lea FP_SRC(%a6),%a0 + mov.l 0x8+0x0(%a6),0x0(%a0) # load ext input + mov.l 0x8+0x4(%a6),0x4(%a0) + mov.l 0x8+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L19_2x + bsr.l sgetman # operand is a NORM + bra.b _L19_6x +_L19_2x: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L19_3x # no + bsr.l src_zero # yes + bra.b _L19_6x +_L19_3x: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L19_4x # no + bsr.l t_operr # yes + bra.b _L19_6x +_L19_4x: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L19_5x # no + bsr.l src_qnan # yes + bra.b _L19_6x +_L19_5x: + bsr.l sgetmand # operand is a DENORM +_L19_6x: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + +######################################################################### +# MONADIC TEMPLATE # +######################################################################### + global _fsincoss_ +_fsincoss_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.s 0x8(%a6),%fp0 # load sgl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L20_2s + bsr.l ssincos # operand is a NORM + bra.b _L20_6s +_L20_2s: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L20_3s # no + bsr.l ssincosz # yes + bra.b _L20_6s +_L20_3s: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L20_4s # no + bsr.l ssincosi # yes + bra.b _L20_6s +_L20_4s: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L20_5s # no + bsr.l ssincosqnan # yes + bra.b _L20_6s +_L20_5s: + bsr.l ssincosd # operand is a DENORM +_L20_6s: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x &0x03,-(%sp) # store off fp0/fp1 + fmovm.x (%sp)+,&0x40 # fp0 now in fp1 + fmovm.x (%sp)+,&0x80 # fp1 now in fp0 + unlk %a6 + rts + + global _fsincosd_ +_fsincosd_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.d 0x8(%a6),%fp0 # load dbl input + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + mov.b %d1,STAG(%a6) + tst.b %d1 + bne.b _L20_2d + bsr.l ssincos # operand is a NORM + bra.b _L20_6d +_L20_2d: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L20_3d # no + bsr.l ssincosz # yes + bra.b _L20_6d +_L20_3d: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L20_4d # no + bsr.l ssincosi # yes + bra.b _L20_6d +_L20_4d: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L20_5d # no + bsr.l ssincosqnan # yes + bra.b _L20_6d +_L20_5d: + bsr.l ssincosd # operand is a DENORM +_L20_6d: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x &0x03,-(%sp) # store off fp0/fp1 + fmovm.x (%sp)+,&0x40 # fp0 now in fp1 + fmovm.x (%sp)+,&0x80 # fp1 now in fp0 + unlk %a6 + rts + + global _fsincosx_ +_fsincosx_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + lea FP_SRC(%a6),%a0 + mov.l 0x8+0x0(%a6),0x0(%a0) # load ext input + mov.l 0x8+0x4(%a6),0x4(%a0) + mov.l 0x8+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.b %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + tst.b %d1 + bne.b _L20_2x + bsr.l ssincos # operand is a NORM + bra.b _L20_6x +_L20_2x: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L20_3x # no + bsr.l ssincosz # yes + bra.b _L20_6x +_L20_3x: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L20_4x # no + bsr.l ssincosi # yes + bra.b _L20_6x +_L20_4x: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L20_5x # no + bsr.l ssincosqnan # yes + bra.b _L20_6x +_L20_5x: + bsr.l ssincosd # operand is a DENORM +_L20_6x: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x &0x03,-(%sp) # store off fp0/fp1 + fmovm.x (%sp)+,&0x40 # fp0 now in fp1 + fmovm.x (%sp)+,&0x80 # fp1 now in fp0 + unlk %a6 + rts + + +######################################################################### +# DYADIC TEMPLATE # +######################################################################### + global _frems_ +_frems_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.s 0x8(%a6),%fp0 # load sgl dst + fmov.x %fp0,FP_DST(%a6) + lea FP_DST(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,DTAG(%a6) + + fmov.s 0xc(%a6),%fp0 # load sgl src + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.l %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + lea FP_SRC(%a6),%a0 # pass ptr to src + lea FP_DST(%a6),%a1 # pass ptr to dst + + tst.b %d1 + bne.b _L21_2s + bsr.l srem_snorm # operand is a NORM + bra.b _L21_6s +_L21_2s: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L21_3s # no + bsr.l srem_szero # yes + bra.b _L21_6s +_L21_3s: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L21_4s # no + bsr.l srem_sinf # yes + bra.b _L21_6s +_L21_4s: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L21_5s # no + bsr.l sop_sqnan # yes + bra.b _L21_6s +_L21_5s: + bsr.l srem_sdnrm # operand is a DENORM +_L21_6s: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fremd_ +_fremd_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.d 0x8(%a6),%fp0 # load dbl dst + fmov.x %fp0,FP_DST(%a6) + lea FP_DST(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,DTAG(%a6) + + fmov.d 0x10(%a6),%fp0 # load dbl src + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.l %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + lea FP_SRC(%a6),%a0 # pass ptr to src + lea FP_DST(%a6),%a1 # pass ptr to dst + + tst.b %d1 + bne.b _L21_2d + bsr.l srem_snorm # operand is a NORM + bra.b _L21_6d +_L21_2d: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L21_3d # no + bsr.l srem_szero # yes + bra.b _L21_6d +_L21_3d: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L21_4d # no + bsr.l srem_sinf # yes + bra.b _L21_6d +_L21_4d: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L21_5d # no + bsr.l sop_sqnan # yes + bra.b _L21_6d +_L21_5d: + bsr.l srem_sdnrm # operand is a DENORM +_L21_6d: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fremx_ +_fremx_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + lea FP_DST(%a6),%a0 + mov.l 0x8+0x0(%a6),0x0(%a0) # load ext dst + mov.l 0x8+0x4(%a6),0x4(%a0) + mov.l 0x8+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,DTAG(%a6) + + lea FP_SRC(%a6),%a0 + mov.l 0x14+0x0(%a6),0x0(%a0) # load ext src + mov.l 0x14+0x4(%a6),0x4(%a0) + mov.l 0x14+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.l %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + lea FP_SRC(%a6),%a0 # pass ptr to src + lea FP_DST(%a6),%a1 # pass ptr to dst + + tst.b %d1 + bne.b _L21_2x + bsr.l srem_snorm # operand is a NORM + bra.b _L21_6x +_L21_2x: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L21_3x # no + bsr.l srem_szero # yes + bra.b _L21_6x +_L21_3x: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L21_4x # no + bsr.l srem_sinf # yes + bra.b _L21_6x +_L21_4x: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L21_5x # no + bsr.l sop_sqnan # yes + bra.b _L21_6x +_L21_5x: + bsr.l srem_sdnrm # operand is a DENORM +_L21_6x: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + +######################################################################### +# DYADIC TEMPLATE # +######################################################################### + global _fmods_ +_fmods_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.s 0x8(%a6),%fp0 # load sgl dst + fmov.x %fp0,FP_DST(%a6) + lea FP_DST(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,DTAG(%a6) + + fmov.s 0xc(%a6),%fp0 # load sgl src + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.l %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + lea FP_SRC(%a6),%a0 # pass ptr to src + lea FP_DST(%a6),%a1 # pass ptr to dst + + tst.b %d1 + bne.b _L22_2s + bsr.l smod_snorm # operand is a NORM + bra.b _L22_6s +_L22_2s: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L22_3s # no + bsr.l smod_szero # yes + bra.b _L22_6s +_L22_3s: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L22_4s # no + bsr.l smod_sinf # yes + bra.b _L22_6s +_L22_4s: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L22_5s # no + bsr.l sop_sqnan # yes + bra.b _L22_6s +_L22_5s: + bsr.l smod_sdnrm # operand is a DENORM +_L22_6s: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fmodd_ +_fmodd_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.d 0x8(%a6),%fp0 # load dbl dst + fmov.x %fp0,FP_DST(%a6) + lea FP_DST(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,DTAG(%a6) + + fmov.d 0x10(%a6),%fp0 # load dbl src + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.l %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + lea FP_SRC(%a6),%a0 # pass ptr to src + lea FP_DST(%a6),%a1 # pass ptr to dst + + tst.b %d1 + bne.b _L22_2d + bsr.l smod_snorm # operand is a NORM + bra.b _L22_6d +_L22_2d: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L22_3d # no + bsr.l smod_szero # yes + bra.b _L22_6d +_L22_3d: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L22_4d # no + bsr.l smod_sinf # yes + bra.b _L22_6d +_L22_4d: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L22_5d # no + bsr.l sop_sqnan # yes + bra.b _L22_6d +_L22_5d: + bsr.l smod_sdnrm # operand is a DENORM +_L22_6d: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fmodx_ +_fmodx_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + lea FP_DST(%a6),%a0 + mov.l 0x8+0x0(%a6),0x0(%a0) # load ext dst + mov.l 0x8+0x4(%a6),0x4(%a0) + mov.l 0x8+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,DTAG(%a6) + + lea FP_SRC(%a6),%a0 + mov.l 0x14+0x0(%a6),0x0(%a0) # load ext src + mov.l 0x14+0x4(%a6),0x4(%a0) + mov.l 0x14+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.l %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + lea FP_SRC(%a6),%a0 # pass ptr to src + lea FP_DST(%a6),%a1 # pass ptr to dst + + tst.b %d1 + bne.b _L22_2x + bsr.l smod_snorm # operand is a NORM + bra.b _L22_6x +_L22_2x: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L22_3x # no + bsr.l smod_szero # yes + bra.b _L22_6x +_L22_3x: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L22_4x # no + bsr.l smod_sinf # yes + bra.b _L22_6x +_L22_4x: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L22_5x # no + bsr.l sop_sqnan # yes + bra.b _L22_6x +_L22_5x: + bsr.l smod_sdnrm # operand is a DENORM +_L22_6x: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + +######################################################################### +# DYADIC TEMPLATE # +######################################################################### + global _fscales_ +_fscales_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.s 0x8(%a6),%fp0 # load sgl dst + fmov.x %fp0,FP_DST(%a6) + lea FP_DST(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,DTAG(%a6) + + fmov.s 0xc(%a6),%fp0 # load sgl src + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.l %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + lea FP_SRC(%a6),%a0 # pass ptr to src + lea FP_DST(%a6),%a1 # pass ptr to dst + + tst.b %d1 + bne.b _L23_2s + bsr.l sscale_snorm # operand is a NORM + bra.b _L23_6s +_L23_2s: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L23_3s # no + bsr.l sscale_szero # yes + bra.b _L23_6s +_L23_3s: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L23_4s # no + bsr.l sscale_sinf # yes + bra.b _L23_6s +_L23_4s: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L23_5s # no + bsr.l sop_sqnan # yes + bra.b _L23_6s +_L23_5s: + bsr.l sscale_sdnrm # operand is a DENORM +_L23_6s: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fscaled_ +_fscaled_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + fmov.d 0x8(%a6),%fp0 # load dbl dst + fmov.x %fp0,FP_DST(%a6) + lea FP_DST(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,DTAG(%a6) + + fmov.d 0x10(%a6),%fp0 # load dbl src + fmov.x %fp0,FP_SRC(%a6) + lea FP_SRC(%a6),%a0 + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.l %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + lea FP_SRC(%a6),%a0 # pass ptr to src + lea FP_DST(%a6),%a1 # pass ptr to dst + + tst.b %d1 + bne.b _L23_2d + bsr.l sscale_snorm # operand is a NORM + bra.b _L23_6d +_L23_2d: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L23_3d # no + bsr.l sscale_szero # yes + bra.b _L23_6d +_L23_3d: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L23_4d # no + bsr.l sscale_sinf # yes + bra.b _L23_6d +_L23_4d: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L23_5d # no + bsr.l sop_sqnan # yes + bra.b _L23_6d +_L23_5d: + bsr.l sscale_sdnrm # operand is a DENORM +_L23_6d: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + global _fscalex_ +_fscalex_: + link %a6,&-LOCAL_SIZE + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FP0(%a6) # save fp0/fp1 + + fmov.l &0x0,%fpcr # zero FPCR + +# +# copy, convert, and tag input argument +# + lea FP_DST(%a6),%a0 + mov.l 0x8+0x0(%a6),0x0(%a0) # load ext dst + mov.l 0x8+0x4(%a6),0x4(%a0) + mov.l 0x8+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,DTAG(%a6) + + lea FP_SRC(%a6),%a0 + mov.l 0x14+0x0(%a6),0x0(%a0) # load ext src + mov.l 0x14+0x4(%a6),0x4(%a0) + mov.l 0x14+0x8(%a6),0x8(%a0) + bsr.l tag # fetch operand type + mov.b %d0,STAG(%a6) + mov.l %d0,%d1 + + andi.l &0x00ff00ff,USER_FPSR(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd mode,prec + + lea FP_SRC(%a6),%a0 # pass ptr to src + lea FP_DST(%a6),%a1 # pass ptr to dst + + tst.b %d1 + bne.b _L23_2x + bsr.l sscale_snorm # operand is a NORM + bra.b _L23_6x +_L23_2x: + cmpi.b %d1,&ZERO # is operand a ZERO? + bne.b _L23_3x # no + bsr.l sscale_szero # yes + bra.b _L23_6x +_L23_3x: + cmpi.b %d1,&INF # is operand an INF? + bne.b _L23_4x # no + bsr.l sscale_sinf # yes + bra.b _L23_6x +_L23_4x: + cmpi.b %d1,&QNAN # is operand a QNAN? + bne.b _L23_5x # no + bsr.l sop_sqnan # yes + bra.b _L23_6x +_L23_5x: + bsr.l sscale_sdnrm # operand is a DENORM +_L23_6x: + +# +# Result is now in FP0 +# + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr # restore ctrl regs + fmovm.x EXC_FP1(%a6),&0x40 # restore fp1 + unlk %a6 + rts + + +######################################################################### +# ssin(): computes the sine of a normalized input # +# ssind(): computes the sine of a denormalized input # +# scos(): computes the cosine of a normalized input # +# scosd(): computes the cosine of a denormalized input # +# ssincos(): computes the sine and cosine of a normalized input # +# ssincosd(): computes the sine and cosine of a denormalized input # +# # +# INPUT *************************************************************** # +# a0 = pointer to extended precision input # +# d0 = round precision,mode # +# # +# OUTPUT ************************************************************** # +# fp0 = sin(X) or cos(X) # +# # +# For ssincos(X): # +# fp0 = sin(X) # +# fp1 = cos(X) # +# # +# ACCURACY and MONOTONICITY ******************************************* # +# The returned result is within 1 ulp in 64 significant bit, i.e. # +# within 0.5001 ulp to 53 bits if the result is subsequently # +# rounded to double precision. The result is provably monotonic # +# in double precision. # +# # +# ALGORITHM *********************************************************** # +# # +# SIN and COS: # +# 1. If SIN is invoked, set AdjN := 0; otherwise, set AdjN := 1. # +# # +# 2. If |X| >= 15Pi or |X| < 2**(-40), go to 7. # +# # +# 3. Decompose X as X = N(Pi/2) + r where |r| <= Pi/4. Let # +# k = N mod 4, so in particular, k = 0,1,2,or 3. # +# Overwrite k by k := k + AdjN. # +# # +# 4. If k is even, go to 6. # +# # +# 5. (k is odd) Set j := (k-1)/2, sgn := (-1)**j. # +# Return sgn*cos(r) where cos(r) is approximated by an # +# even polynomial in r, 1 + r*r*(B1+s*(B2+ ... + s*B8)), # +# s = r*r. # +# Exit. # +# # +# 6. (k is even) Set j := k/2, sgn := (-1)**j. Return sgn*sin(r) # +# where sin(r) is approximated by an odd polynomial in r # +# r + r*s*(A1+s*(A2+ ... + s*A7)), s = r*r. # +# Exit. # +# # +# 7. If |X| > 1, go to 9. # +# # +# 8. (|X|<2**(-40)) If SIN is invoked, return X; # +# otherwise return 1. # +# # +# 9. Overwrite X by X := X rem 2Pi. Now that |X| <= Pi, # +# go back to 3. # +# # +# SINCOS: # +# 1. If |X| >= 15Pi or |X| < 2**(-40), go to 6. # +# # +# 2. Decompose X as X = N(Pi/2) + r where |r| <= Pi/4. Let # +# k = N mod 4, so in particular, k = 0,1,2,or 3. # +# # +# 3. If k is even, go to 5. # +# # +# 4. (k is odd) Set j1 := (k-1)/2, j2 := j1 (EOR) (k mod 2), ie. # +# j1 exclusive or with the l.s.b. of k. # +# sgn1 := (-1)**j1, sgn2 := (-1)**j2. # +# SIN(X) = sgn1 * cos(r) and COS(X) = sgn2*sin(r) where # +# sin(r) and cos(r) are computed as odd and even # +# polynomials in r, respectively. Exit # +# # +# 5. (k is even) Set j1 := k/2, sgn1 := (-1)**j1. # +# SIN(X) = sgn1 * sin(r) and COS(X) = sgn1*cos(r) where # +# sin(r) and cos(r) are computed as odd and even # +# polynomials in r, respectively. Exit # +# # +# 6. If |X| > 1, go to 8. # +# # +# 7. (|X|<2**(-40)) SIN(X) = X and COS(X) = 1. Exit. # +# # +# 8. Overwrite X by X := X rem 2Pi. Now that |X| <= Pi, # +# go back to 2. # +# # +######################################################################### + +SINA7: long 0xBD6AAA77,0xCCC994F5 +SINA6: long 0x3DE61209,0x7AAE8DA1 +SINA5: long 0xBE5AE645,0x2A118AE4 +SINA4: long 0x3EC71DE3,0xA5341531 +SINA3: long 0xBF2A01A0,0x1A018B59,0x00000000,0x00000000 +SINA2: long 0x3FF80000,0x88888888,0x888859AF,0x00000000 +SINA1: long 0xBFFC0000,0xAAAAAAAA,0xAAAAAA99,0x00000000 + +COSB8: long 0x3D2AC4D0,0xD6011EE3 +COSB7: long 0xBDA9396F,0x9F45AC19 +COSB6: long 0x3E21EED9,0x0612C972 +COSB5: long 0xBE927E4F,0xB79D9FCF +COSB4: long 0x3EFA01A0,0x1A01D423,0x00000000,0x00000000 +COSB3: long 0xBFF50000,0xB60B60B6,0x0B61D438,0x00000000 +COSB2: long 0x3FFA0000,0xAAAAAAAA,0xAAAAAB5E +COSB1: long 0xBF000000 + + set INARG,FP_SCR0 + + set X,FP_SCR0 +# set XDCARE,X+2 + set XFRAC,X+4 + + set RPRIME,FP_SCR0 + set SPRIME,FP_SCR1 + + set POSNEG1,L_SCR1 + set TWOTO63,L_SCR1 + + set ENDFLAG,L_SCR2 + set INT,L_SCR2 + + set ADJN,L_SCR3 + +############################################ + global ssin +ssin: + mov.l &0,ADJN(%a6) # yes; SET ADJN TO 0 + bra.b SINBGN + +############################################ + global scos +scos: + mov.l &1,ADJN(%a6) # yes; SET ADJN TO 1 + +############################################ +SINBGN: +#--SAVE FPCR, FP1. CHECK IF |X| IS TOO SMALL OR LARGE + + fmov.x (%a0),%fp0 # LOAD INPUT + fmov.x %fp0,X(%a6) # save input at X + +# "COMPACTIFY" X + mov.l (%a0),%d1 # put exp in hi word + mov.w 4(%a0),%d1 # fetch hi(man) + and.l &0x7FFFFFFF,%d1 # strip sign + + cmpi.l %d1,&0x3FD78000 # is |X| >= 2**(-40)? + bge.b SOK1 # no + bra.w SINSM # yes; input is very small + +SOK1: + cmp.l %d1,&0x4004BC7E # is |X| < 15 PI? + blt.b SINMAIN # no + bra.w SREDUCEX # yes; input is very large + +#--THIS IS THE USUAL CASE, |X| <= 15 PI. +#--THE ARGUMENT REDUCTION IS DONE BY TABLE LOOK UP. +SINMAIN: + fmov.x %fp0,%fp1 + fmul.d TWOBYPI(%pc),%fp1 # X*2/PI + + lea PITBL+0x200(%pc),%a1 # TABLE OF N*PI/2, N = -32,...,32 + + fmov.l %fp1,INT(%a6) # CONVERT TO INTEGER + + mov.l INT(%a6),%d1 # make a copy of N + asl.l &4,%d1 # N *= 16 + add.l %d1,%a1 # tbl_addr = a1 + (N*16) + +# A1 IS THE ADDRESS OF N*PIBY2 +# ...WHICH IS IN TWO PIECES Y1 & Y2 + fsub.x (%a1)+,%fp0 # X-Y1 + fsub.s (%a1),%fp0 # fp0 = R = (X-Y1)-Y2 + +SINCONT: +#--continuation from REDUCEX + +#--GET N+ADJN AND SEE IF SIN(R) OR COS(R) IS NEEDED + mov.l INT(%a6),%d1 + add.l ADJN(%a6),%d1 # SEE IF D0 IS ODD OR EVEN + ror.l &1,%d1 # D0 WAS ODD IFF D0 IS NEGATIVE + cmp.l %d1,&0 + blt.w COSPOLY + +#--LET J BE THE LEAST SIG. BIT OF D0, LET SGN := (-1)**J. +#--THEN WE RETURN SGN*SIN(R). SGN*SIN(R) IS COMPUTED BY +#--R' + R'*S*(A1 + S(A2 + S(A3 + S(A4 + ... + SA7)))), WHERE +#--R' = SGN*R, S=R*R. THIS CAN BE REWRITTEN AS +#--R' + R'*S*( [A1+T(A3+T(A5+TA7))] + [S(A2+T(A4+TA6))]) +#--WHERE T=S*S. +#--NOTE THAT A3 THROUGH A7 ARE STORED IN DOUBLE PRECISION +#--WHILE A1 AND A2 ARE IN DOUBLE-EXTENDED FORMAT. +SINPOLY: + fmovm.x &0x0c,-(%sp) # save fp2/fp3 + + fmov.x %fp0,X(%a6) # X IS R + fmul.x %fp0,%fp0 # FP0 IS S + + fmov.d SINA7(%pc),%fp3 + fmov.d SINA6(%pc),%fp2 + + fmov.x %fp0,%fp1 + fmul.x %fp1,%fp1 # FP1 IS T + + ror.l &1,%d1 + and.l &0x80000000,%d1 +# ...LEAST SIG. BIT OF D0 IN SIGN POSITION + eor.l %d1,X(%a6) # X IS NOW R'= SGN*R + + fmul.x %fp1,%fp3 # TA7 + fmul.x %fp1,%fp2 # TA6 + + fadd.d SINA5(%pc),%fp3 # A5+TA7 + fadd.d SINA4(%pc),%fp2 # A4+TA6 + + fmul.x %fp1,%fp3 # T(A5+TA7) + fmul.x %fp1,%fp2 # T(A4+TA6) + + fadd.d SINA3(%pc),%fp3 # A3+T(A5+TA7) + fadd.x SINA2(%pc),%fp2 # A2+T(A4+TA6) + + fmul.x %fp3,%fp1 # T(A3+T(A5+TA7)) + + fmul.x %fp0,%fp2 # S(A2+T(A4+TA6)) + fadd.x SINA1(%pc),%fp1 # A1+T(A3+T(A5+TA7)) + fmul.x X(%a6),%fp0 # R'*S + + fadd.x %fp2,%fp1 # [A1+T(A3+T(A5+TA7))]+[S(A2+T(A4+TA6))] + + fmul.x %fp1,%fp0 # SIN(R')-R' + + fmovm.x (%sp)+,&0x30 # restore fp2/fp3 + + fmov.l %d0,%fpcr # restore users round mode,prec + fadd.x X(%a6),%fp0 # last inst - possible exception set + bra t_inx2 + +#--LET J BE THE LEAST SIG. BIT OF D0, LET SGN := (-1)**J. +#--THEN WE RETURN SGN*COS(R). SGN*COS(R) IS COMPUTED BY +#--SGN + S'*(B1 + S(B2 + S(B3 + S(B4 + ... + SB8)))), WHERE +#--S=R*R AND S'=SGN*S. THIS CAN BE REWRITTEN AS +#--SGN + S'*([B1+T(B3+T(B5+TB7))] + [S(B2+T(B4+T(B6+TB8)))]) +#--WHERE T=S*S. +#--NOTE THAT B4 THROUGH B8 ARE STORED IN DOUBLE PRECISION +#--WHILE B2 AND B3 ARE IN DOUBLE-EXTENDED FORMAT, B1 IS -1/2 +#--AND IS THEREFORE STORED AS SINGLE PRECISION. +COSPOLY: + fmovm.x &0x0c,-(%sp) # save fp2/fp3 + + fmul.x %fp0,%fp0 # FP0 IS S + + fmov.d COSB8(%pc),%fp2 + fmov.d COSB7(%pc),%fp3 + + fmov.x %fp0,%fp1 + fmul.x %fp1,%fp1 # FP1 IS T + + fmov.x %fp0,X(%a6) # X IS S + ror.l &1,%d1 + and.l &0x80000000,%d1 +# ...LEAST SIG. BIT OF D0 IN SIGN POSITION + + fmul.x %fp1,%fp2 # TB8 + + eor.l %d1,X(%a6) # X IS NOW S'= SGN*S + and.l &0x80000000,%d1 + + fmul.x %fp1,%fp3 # TB7 + + or.l &0x3F800000,%d1 # D0 IS SGN IN SINGLE + mov.l %d1,POSNEG1(%a6) + + fadd.d COSB6(%pc),%fp2 # B6+TB8 + fadd.d COSB5(%pc),%fp3 # B5+TB7 + + fmul.x %fp1,%fp2 # T(B6+TB8) + fmul.x %fp1,%fp3 # T(B5+TB7) + + fadd.d COSB4(%pc),%fp2 # B4+T(B6+TB8) + fadd.x COSB3(%pc),%fp3 # B3+T(B5+TB7) + + fmul.x %fp1,%fp2 # T(B4+T(B6+TB8)) + fmul.x %fp3,%fp1 # T(B3+T(B5+TB7)) + + fadd.x COSB2(%pc),%fp2 # B2+T(B4+T(B6+TB8)) + fadd.s COSB1(%pc),%fp1 # B1+T(B3+T(B5+TB7)) + + fmul.x %fp2,%fp0 # S(B2+T(B4+T(B6+TB8))) + + fadd.x %fp1,%fp0 + + fmul.x X(%a6),%fp0 + + fmovm.x (%sp)+,&0x30 # restore fp2/fp3 + + fmov.l %d0,%fpcr # restore users round mode,prec + fadd.s POSNEG1(%a6),%fp0 # last inst - possible exception set + bra t_inx2 + +############################################## + +# SINe: Big OR Small? +#--IF |X| > 15PI, WE USE THE GENERAL ARGUMENT REDUCTION. +#--IF |X| < 2**(-40), RETURN X OR 1. +SINBORS: + cmp.l %d1,&0x3FFF8000 + bgt.l SREDUCEX + +SINSM: + mov.l ADJN(%a6),%d1 + cmp.l %d1,&0 + bgt.b COSTINY + +# here, the operation may underflow iff the precision is sgl or dbl. +# extended denorms are handled through another entry point. +SINTINY: +# mov.w &0x0000,XDCARE(%a6) # JUST IN CASE + + fmov.l %d0,%fpcr # restore users round mode,prec + mov.b &FMOV_OP,%d1 # last inst is MOVE + fmov.x X(%a6),%fp0 # last inst - possible exception set + bra t_catch + +COSTINY: + fmov.s &0x3F800000,%fp0 # fp0 = 1.0 + fmov.l %d0,%fpcr # restore users round mode,prec + fadd.s &0x80800000,%fp0 # last inst - possible exception set + bra t_pinx2 + +################################################ + global ssind +#--SIN(X) = X FOR DENORMALIZED X +ssind: + bra t_extdnrm + +############################################ + global scosd +#--COS(X) = 1 FOR DENORMALIZED X +scosd: + fmov.s &0x3F800000,%fp0 # fp0 = 1.0 + bra t_pinx2 + +################################################## + + global ssincos +ssincos: +#--SET ADJN TO 4 + mov.l &4,ADJN(%a6) + + fmov.x (%a0),%fp0 # LOAD INPUT + fmov.x %fp0,X(%a6) + + mov.l (%a0),%d1 + mov.w 4(%a0),%d1 + and.l &0x7FFFFFFF,%d1 # COMPACTIFY X + + cmp.l %d1,&0x3FD78000 # |X| >= 2**(-40)? + bge.b SCOK1 + bra.w SCSM + +SCOK1: + cmp.l %d1,&0x4004BC7E # |X| < 15 PI? + blt.b SCMAIN + bra.w SREDUCEX + + +#--THIS IS THE USUAL CASE, |X| <= 15 PI. +#--THE ARGUMENT REDUCTION IS DONE BY TABLE LOOK UP. +SCMAIN: + fmov.x %fp0,%fp1 + + fmul.d TWOBYPI(%pc),%fp1 # X*2/PI + + lea PITBL+0x200(%pc),%a1 # TABLE OF N*PI/2, N = -32,...,32 + + fmov.l %fp1,INT(%a6) # CONVERT TO INTEGER + + mov.l INT(%a6),%d1 + asl.l &4,%d1 + add.l %d1,%a1 # ADDRESS OF N*PIBY2, IN Y1, Y2 + + fsub.x (%a1)+,%fp0 # X-Y1 + fsub.s (%a1),%fp0 # FP0 IS R = (X-Y1)-Y2 + +SCCONT: +#--continuation point from REDUCEX + + mov.l INT(%a6),%d1 + ror.l &1,%d1 + cmp.l %d1,&0 # D0 < 0 IFF N IS ODD + bge.w NEVEN + +SNODD: +#--REGISTERS SAVED SO FAR: D0, A0, FP2. + fmovm.x &0x04,-(%sp) # save fp2 + + fmov.x %fp0,RPRIME(%a6) + fmul.x %fp0,%fp0 # FP0 IS S = R*R + fmov.d SINA7(%pc),%fp1 # A7 + fmov.d COSB8(%pc),%fp2 # B8 + fmul.x %fp0,%fp1 # SA7 + fmul.x %fp0,%fp2 # SB8 + + mov.l %d2,-(%sp) + mov.l %d1,%d2 + ror.l &1,%d2 + and.l &0x80000000,%d2 + eor.l %d1,%d2 + and.l &0x80000000,%d2 + + fadd.d SINA6(%pc),%fp1 # A6+SA7 + fadd.d COSB7(%pc),%fp2 # B7+SB8 + + fmul.x %fp0,%fp1 # S(A6+SA7) + eor.l %d2,RPRIME(%a6) + mov.l (%sp)+,%d2 + fmul.x %fp0,%fp2 # S(B7+SB8) + ror.l &1,%d1 + and.l &0x80000000,%d1 + mov.l &0x3F800000,POSNEG1(%a6) + eor.l %d1,POSNEG1(%a6) + + fadd.d SINA5(%pc),%fp1 # A5+S(A6+SA7) + fadd.d COSB6(%pc),%fp2 # B6+S(B7+SB8) + + fmul.x %fp0,%fp1 # S(A5+S(A6+SA7)) + fmul.x %fp0,%fp2 # S(B6+S(B7+SB8)) + fmov.x %fp0,SPRIME(%a6) + + fadd.d SINA4(%pc),%fp1 # A4+S(A5+S(A6+SA7)) + eor.l %d1,SPRIME(%a6) + fadd.d COSB5(%pc),%fp2 # B5+S(B6+S(B7+SB8)) + + fmul.x %fp0,%fp1 # S(A4+...) + fmul.x %fp0,%fp2 # S(B5+...) + + fadd.d SINA3(%pc),%fp1 # A3+S(A4+...) + fadd.d COSB4(%pc),%fp2 # B4+S(B5+...) + + fmul.x %fp0,%fp1 # S(A3+...) + fmul.x %fp0,%fp2 # S(B4+...) + + fadd.x SINA2(%pc),%fp1 # A2+S(A3+...) + fadd.x COSB3(%pc),%fp2 # B3+S(B4+...) + + fmul.x %fp0,%fp1 # S(A2+...) + fmul.x %fp0,%fp2 # S(B3+...) + + fadd.x SINA1(%pc),%fp1 # A1+S(A2+...) + fadd.x COSB2(%pc),%fp2 # B2+S(B3+...) + + fmul.x %fp0,%fp1 # S(A1+...) + fmul.x %fp2,%fp0 # S(B2+...) + + fmul.x RPRIME(%a6),%fp1 # R'S(A1+...) + fadd.s COSB1(%pc),%fp0 # B1+S(B2...) + fmul.x SPRIME(%a6),%fp0 # S'(B1+S(B2+...)) + + fmovm.x (%sp)+,&0x20 # restore fp2 + + fmov.l %d0,%fpcr + fadd.x RPRIME(%a6),%fp1 # COS(X) + bsr sto_cos # store cosine result + fadd.s POSNEG1(%a6),%fp0 # SIN(X) + bra t_inx2 + +NEVEN: +#--REGISTERS SAVED SO FAR: FP2. + fmovm.x &0x04,-(%sp) # save fp2 + + fmov.x %fp0,RPRIME(%a6) + fmul.x %fp0,%fp0 # FP0 IS S = R*R + + fmov.d COSB8(%pc),%fp1 # B8 + fmov.d SINA7(%pc),%fp2 # A7 + + fmul.x %fp0,%fp1 # SB8 + fmov.x %fp0,SPRIME(%a6) + fmul.x %fp0,%fp2 # SA7 + + ror.l &1,%d1 + and.l &0x80000000,%d1 + + fadd.d COSB7(%pc),%fp1 # B7+SB8 + fadd.d SINA6(%pc),%fp2 # A6+SA7 + + eor.l %d1,RPRIME(%a6) + eor.l %d1,SPRIME(%a6) + + fmul.x %fp0,%fp1 # S(B7+SB8) + + or.l &0x3F800000,%d1 + mov.l %d1,POSNEG1(%a6) + + fmul.x %fp0,%fp2 # S(A6+SA7) + + fadd.d COSB6(%pc),%fp1 # B6+S(B7+SB8) + fadd.d SINA5(%pc),%fp2 # A5+S(A6+SA7) + + fmul.x %fp0,%fp1 # S(B6+S(B7+SB8)) + fmul.x %fp0,%fp2 # S(A5+S(A6+SA7)) + + fadd.d COSB5(%pc),%fp1 # B5+S(B6+S(B7+SB8)) + fadd.d SINA4(%pc),%fp2 # A4+S(A5+S(A6+SA7)) + + fmul.x %fp0,%fp1 # S(B5+...) + fmul.x %fp0,%fp2 # S(A4+...) + + fadd.d COSB4(%pc),%fp1 # B4+S(B5+...) + fadd.d SINA3(%pc),%fp2 # A3+S(A4+...) + + fmul.x %fp0,%fp1 # S(B4+...) + fmul.x %fp0,%fp2 # S(A3+...) + + fadd.x COSB3(%pc),%fp1 # B3+S(B4+...) + fadd.x SINA2(%pc),%fp2 # A2+S(A3+...) + + fmul.x %fp0,%fp1 # S(B3+...) + fmul.x %fp0,%fp2 # S(A2+...) + + fadd.x COSB2(%pc),%fp1 # B2+S(B3+...) + fadd.x SINA1(%pc),%fp2 # A1+S(A2+...) + + fmul.x %fp0,%fp1 # S(B2+...) + fmul.x %fp2,%fp0 # s(a1+...) + + + fadd.s COSB1(%pc),%fp1 # B1+S(B2...) + fmul.x RPRIME(%a6),%fp0 # R'S(A1+...) + fmul.x SPRIME(%a6),%fp1 # S'(B1+S(B2+...)) + + fmovm.x (%sp)+,&0x20 # restore fp2 + + fmov.l %d0,%fpcr + fadd.s POSNEG1(%a6),%fp1 # COS(X) + bsr sto_cos # store cosine result + fadd.x RPRIME(%a6),%fp0 # SIN(X) + bra t_inx2 + +################################################ + +SCBORS: + cmp.l %d1,&0x3FFF8000 + bgt.w SREDUCEX + +################################################ + +SCSM: +# mov.w &0x0000,XDCARE(%a6) + fmov.s &0x3F800000,%fp1 + + fmov.l %d0,%fpcr + fsub.s &0x00800000,%fp1 + bsr sto_cos # store cosine result + fmov.l %fpcr,%d0 # d0 must have fpcr,too + mov.b &FMOV_OP,%d1 # last inst is MOVE + fmov.x X(%a6),%fp0 + bra t_catch + +############################################## + + global ssincosd +#--SIN AND COS OF X FOR DENORMALIZED X +ssincosd: + mov.l %d0,-(%sp) # save d0 + fmov.s &0x3F800000,%fp1 + bsr sto_cos # store cosine result + mov.l (%sp)+,%d0 # restore d0 + bra t_extdnrm + +############################################ + +#--WHEN REDUCEX IS USED, THE CODE WILL INEVITABLY BE SLOW. +#--THIS REDUCTION METHOD, HOWEVER, IS MUCH FASTER THAN USING +#--THE REMAINDER INSTRUCTION WHICH IS NOW IN SOFTWARE. +SREDUCEX: + fmovm.x &0x3c,-(%sp) # save {fp2-fp5} + mov.l %d2,-(%sp) # save d2 + fmov.s &0x00000000,%fp1 # fp1 = 0 + +#--If compact form of abs(arg) in d0=$7ffeffff, argument is so large that +#--there is a danger of unwanted overflow in first LOOP iteration. In this +#--case, reduce argument by one remainder step to make subsequent reduction +#--safe. + cmp.l %d1,&0x7ffeffff # is arg dangerously large? + bne.b SLOOP # no + +# yes; create 2**16383*PI/2 + mov.w &0x7ffe,FP_SCR0_EX(%a6) + mov.l &0xc90fdaa2,FP_SCR0_HI(%a6) + clr.l FP_SCR0_LO(%a6) + +# create low half of 2**16383*PI/2 at FP_SCR1 + mov.w &0x7fdc,FP_SCR1_EX(%a6) + mov.l &0x85a308d3,FP_SCR1_HI(%a6) + clr.l FP_SCR1_LO(%a6) + + ftest.x %fp0 # test sign of argument + fblt.w sred_neg + + or.b &0x80,FP_SCR0_EX(%a6) # positive arg + or.b &0x80,FP_SCR1_EX(%a6) +sred_neg: + fadd.x FP_SCR0(%a6),%fp0 # high part of reduction is exact + fmov.x %fp0,%fp1 # save high result in fp1 + fadd.x FP_SCR1(%a6),%fp0 # low part of reduction + fsub.x %fp0,%fp1 # determine low component of result + fadd.x FP_SCR1(%a6),%fp1 # fp0/fp1 are reduced argument. + +#--ON ENTRY, FP0 IS X, ON RETURN, FP0 IS X REM PI/2, |X| <= PI/4. +#--integer quotient will be stored in N +#--Intermeditate remainder is 66-bit long; (R,r) in (FP0,FP1) +SLOOP: + fmov.x %fp0,INARG(%a6) # +-2**K * F, 1 <= F < 2 + mov.w INARG(%a6),%d1 + mov.l %d1,%a1 # save a copy of D0 + and.l &0x00007FFF,%d1 + sub.l &0x00003FFF,%d1 # d0 = K + cmp.l %d1,&28 + ble.b SLASTLOOP +SCONTLOOP: + sub.l &27,%d1 # d0 = L := K-27 + mov.b &0,ENDFLAG(%a6) + bra.b SWORK +SLASTLOOP: + clr.l %d1 # d0 = L := 0 + mov.b &1,ENDFLAG(%a6) + +SWORK: +#--FIND THE REMAINDER OF (R,r) W.R.T. 2**L * (PI/2). L IS SO CHOSEN +#--THAT INT( X * (2/PI) / 2**(L) ) < 2**29. + +#--CREATE 2**(-L) * (2/PI), SIGN(INARG)*2**(63), +#--2**L * (PIby2_1), 2**L * (PIby2_2) + + mov.l &0x00003FFE,%d2 # BIASED EXP OF 2/PI + sub.l %d1,%d2 # BIASED EXP OF 2**(-L)*(2/PI) + + mov.l &0xA2F9836E,FP_SCR0_HI(%a6) + mov.l &0x4E44152A,FP_SCR0_LO(%a6) + mov.w %d2,FP_SCR0_EX(%a6) # FP_SCR0 = 2**(-L)*(2/PI) + + fmov.x %fp0,%fp2 + fmul.x FP_SCR0(%a6),%fp2 # fp2 = X * 2**(-L)*(2/PI) + +#--WE MUST NOW FIND INT(FP2). SINCE WE NEED THIS VALUE IN +#--FLOATING POINT FORMAT, THE TWO FMOVE'S FMOVE.L FP <--> N +#--WILL BE TOO INEFFICIENT. THE WAY AROUND IT IS THAT +#--(SIGN(INARG)*2**63 + FP2) - SIGN(INARG)*2**63 WILL GIVE +#--US THE DESIRED VALUE IN FLOATING POINT. + mov.l %a1,%d2 + swap %d2 + and.l &0x80000000,%d2 + or.l &0x5F000000,%d2 # d2 = SIGN(INARG)*2**63 IN SGL + mov.l %d2,TWOTO63(%a6) + fadd.s TWOTO63(%a6),%fp2 # THE FRACTIONAL PART OF FP1 IS ROUNDED + fsub.s TWOTO63(%a6),%fp2 # fp2 = N +# fint.x %fp2 + +#--CREATING 2**(L)*Piby2_1 and 2**(L)*Piby2_2 + mov.l %d1,%d2 # d2 = L + + add.l &0x00003FFF,%d2 # BIASED EXP OF 2**L * (PI/2) + mov.w %d2,FP_SCR0_EX(%a6) + mov.l &0xC90FDAA2,FP_SCR0_HI(%a6) + clr.l FP_SCR0_LO(%a6) # FP_SCR0 = 2**(L) * Piby2_1 + + add.l &0x00003FDD,%d1 + mov.w %d1,FP_SCR1_EX(%a6) + mov.l &0x85A308D3,FP_SCR1_HI(%a6) + clr.l FP_SCR1_LO(%a6) # FP_SCR1 = 2**(L) * Piby2_2 + + mov.b ENDFLAG(%a6),%d1 + +#--We are now ready to perform (R+r) - N*P1 - N*P2, P1 = 2**(L) * Piby2_1 and +#--P2 = 2**(L) * Piby2_2 + fmov.x %fp2,%fp4 # fp4 = N + fmul.x FP_SCR0(%a6),%fp4 # fp4 = W = N*P1 + fmov.x %fp2,%fp5 # fp5 = N + fmul.x FP_SCR1(%a6),%fp5 # fp5 = w = N*P2 + fmov.x %fp4,%fp3 # fp3 = W = N*P1 + +#--we want P+p = W+w but |p| <= half ulp of P +#--Then, we need to compute A := R-P and a := r-p + fadd.x %fp5,%fp3 # fp3 = P + fsub.x %fp3,%fp4 # fp4 = W-P + + fsub.x %fp3,%fp0 # fp0 = A := R - P + fadd.x %fp5,%fp4 # fp4 = p = (W-P)+w + + fmov.x %fp0,%fp3 # fp3 = A + fsub.x %fp4,%fp1 # fp1 = a := r - p + +#--Now we need to normalize (A,a) to "new (R,r)" where R+r = A+a but +#--|r| <= half ulp of R. + fadd.x %fp1,%fp0 # fp0 = R := A+a +#--No need to calculate r if this is the last loop + cmp.b %d1,&0 + bgt.w SRESTORE + +#--Need to calculate r + fsub.x %fp0,%fp3 # fp3 = A-R + fadd.x %fp3,%fp1 # fp1 = r := (A-R)+a + bra.w SLOOP + +SRESTORE: + fmov.l %fp2,INT(%a6) + mov.l (%sp)+,%d2 # restore d2 + fmovm.x (%sp)+,&0x3c # restore {fp2-fp5} + + mov.l ADJN(%a6),%d1 + cmp.l %d1,&4 + + blt.w SINCONT + bra.w SCCONT + +######################################################################### +# stan(): computes the tangent of a normalized input # +# stand(): computes the tangent of a denormalized input # +# # +# INPUT *************************************************************** # +# a0 = pointer to extended precision input # +# d0 = round precision,mode # +# # +# OUTPUT ************************************************************** # +# fp0 = tan(X) # +# # +# ACCURACY and MONOTONICITY ******************************************* # +# The returned result is within 3 ulp in 64 significant bit, i.e. # +# within 0.5001 ulp to 53 bits if the result is subsequently # +# rounded to double precision. The result is provably monotonic # +# in double precision. # +# # +# ALGORITHM *********************************************************** # +# # +# 1. If |X| >= 15Pi or |X| < 2**(-40), go to 6. # +# # +# 2. Decompose X as X = N(Pi/2) + r where |r| <= Pi/4. Let # +# k = N mod 2, so in particular, k = 0 or 1. # +# # +# 3. If k is odd, go to 5. # +# # +# 4. (k is even) Tan(X) = tan(r) and tan(r) is approximated by a # +# rational function U/V where # +# U = r + r*s*(P1 + s*(P2 + s*P3)), and # +# V = 1 + s*(Q1 + s*(Q2 + s*(Q3 + s*Q4))), s = r*r. # +# Exit. # +# # +# 4. (k is odd) Tan(X) = -cot(r). Since tan(r) is approximated by # +# a rational function U/V where # +# U = r + r*s*(P1 + s*(P2 + s*P3)), and # +# V = 1 + s*(Q1 + s*(Q2 + s*(Q3 + s*Q4))), s = r*r, # +# -Cot(r) = -V/U. Exit. # +# # +# 6. If |X| > 1, go to 8. # +# # +# 7. (|X|<2**(-40)) Tan(X) = X. Exit. # +# # +# 8. Overwrite X by X := X rem 2Pi. Now that |X| <= Pi, go back # +# to 2. # +# # +######################################################################### + +TANQ4: + long 0x3EA0B759,0xF50F8688 +TANP3: + long 0xBEF2BAA5,0xA8924F04 + +TANQ3: + long 0xBF346F59,0xB39BA65F,0x00000000,0x00000000 + +TANP2: + long 0x3FF60000,0xE073D3FC,0x199C4A00,0x00000000 + +TANQ2: + long 0x3FF90000,0xD23CD684,0x15D95FA1,0x00000000 + +TANP1: + long 0xBFFC0000,0x8895A6C5,0xFB423BCA,0x00000000 + +TANQ1: + long 0xBFFD0000,0xEEF57E0D,0xA84BC8CE,0x00000000 + +INVTWOPI: + long 0x3FFC0000,0xA2F9836E,0x4E44152A,0x00000000 + +TWOPI1: + long 0x40010000,0xC90FDAA2,0x00000000,0x00000000 +TWOPI2: + long 0x3FDF0000,0x85A308D4,0x00000000,0x00000000 + +#--N*PI/2, -32 <= N <= 32, IN A LEADING TERM IN EXT. AND TRAILING +#--TERM IN SGL. NOTE THAT PI IS 64-BIT LONG, THUS N*PI/2 IS AT +#--MOST 69 BITS LONG. +# global PITBL +PITBL: + long 0xC0040000,0xC90FDAA2,0x2168C235,0x21800000 + long 0xC0040000,0xC2C75BCD,0x105D7C23,0xA0D00000 + long 0xC0040000,0xBC7EDCF7,0xFF523611,0xA1E80000 + long 0xC0040000,0xB6365E22,0xEE46F000,0x21480000 + long 0xC0040000,0xAFEDDF4D,0xDD3BA9EE,0xA1200000 + long 0xC0040000,0xA9A56078,0xCC3063DD,0x21FC0000 + long 0xC0040000,0xA35CE1A3,0xBB251DCB,0x21100000 + long 0xC0040000,0x9D1462CE,0xAA19D7B9,0xA1580000 + long 0xC0040000,0x96CBE3F9,0x990E91A8,0x21E00000 + long 0xC0040000,0x90836524,0x88034B96,0x20B00000 + long 0xC0040000,0x8A3AE64F,0x76F80584,0xA1880000 + long 0xC0040000,0x83F2677A,0x65ECBF73,0x21C40000 + long 0xC0030000,0xFB53D14A,0xA9C2F2C2,0x20000000 + long 0xC0030000,0xEEC2D3A0,0x87AC669F,0x21380000 + long 0xC0030000,0xE231D5F6,0x6595DA7B,0xA1300000 + long 0xC0030000,0xD5A0D84C,0x437F4E58,0x9FC00000 + long 0xC0030000,0xC90FDAA2,0x2168C235,0x21000000 + long 0xC0030000,0xBC7EDCF7,0xFF523611,0xA1680000 + long 0xC0030000,0xAFEDDF4D,0xDD3BA9EE,0xA0A00000 + long 0xC0030000,0xA35CE1A3,0xBB251DCB,0x20900000 + long 0xC0030000,0x96CBE3F9,0x990E91A8,0x21600000 + long 0xC0030000,0x8A3AE64F,0x76F80584,0xA1080000 + long 0xC0020000,0xFB53D14A,0xA9C2F2C2,0x1F800000 + long 0xC0020000,0xE231D5F6,0x6595DA7B,0xA0B00000 + long 0xC0020000,0xC90FDAA2,0x2168C235,0x20800000 + long 0xC0020000,0xAFEDDF4D,0xDD3BA9EE,0xA0200000 + long 0xC0020000,0x96CBE3F9,0x990E91A8,0x20E00000 + long 0xC0010000,0xFB53D14A,0xA9C2F2C2,0x1F000000 + long 0xC0010000,0xC90FDAA2,0x2168C235,0x20000000 + long 0xC0010000,0x96CBE3F9,0x990E91A8,0x20600000 + long 0xC0000000,0xC90FDAA2,0x2168C235,0x1F800000 + long 0xBFFF0000,0xC90FDAA2,0x2168C235,0x1F000000 + long 0x00000000,0x00000000,0x00000000,0x00000000 + long 0x3FFF0000,0xC90FDAA2,0x2168C235,0x9F000000 + long 0x40000000,0xC90FDAA2,0x2168C235,0x9F800000 + long 0x40010000,0x96CBE3F9,0x990E91A8,0xA0600000 + long 0x40010000,0xC90FDAA2,0x2168C235,0xA0000000 + long 0x40010000,0xFB53D14A,0xA9C2F2C2,0x9F000000 + long 0x40020000,0x96CBE3F9,0x990E91A8,0xA0E00000 + long 0x40020000,0xAFEDDF4D,0xDD3BA9EE,0x20200000 + long 0x40020000,0xC90FDAA2,0x2168C235,0xA0800000 + long 0x40020000,0xE231D5F6,0x6595DA7B,0x20B00000 + long 0x40020000,0xFB53D14A,0xA9C2F2C2,0x9F800000 + long 0x40030000,0x8A3AE64F,0x76F80584,0x21080000 + long 0x40030000,0x96CBE3F9,0x990E91A8,0xA1600000 + long 0x40030000,0xA35CE1A3,0xBB251DCB,0xA0900000 + long 0x40030000,0xAFEDDF4D,0xDD3BA9EE,0x20A00000 + long 0x40030000,0xBC7EDCF7,0xFF523611,0x21680000 + long 0x40030000,0xC90FDAA2,0x2168C235,0xA1000000 + long 0x40030000,0xD5A0D84C,0x437F4E58,0x1FC00000 + long 0x40030000,0xE231D5F6,0x6595DA7B,0x21300000 + long 0x40030000,0xEEC2D3A0,0x87AC669F,0xA1380000 + long 0x40030000,0xFB53D14A,0xA9C2F2C2,0xA0000000 + long 0x40040000,0x83F2677A,0x65ECBF73,0xA1C40000 + long 0x40040000,0x8A3AE64F,0x76F80584,0x21880000 + long 0x40040000,0x90836524,0x88034B96,0xA0B00000 + long 0x40040000,0x96CBE3F9,0x990E91A8,0xA1E00000 + long 0x40040000,0x9D1462CE,0xAA19D7B9,0x21580000 + long 0x40040000,0xA35CE1A3,0xBB251DCB,0xA1100000 + long 0x40040000,0xA9A56078,0xCC3063DD,0xA1FC0000 + long 0x40040000,0xAFEDDF4D,0xDD3BA9EE,0x21200000 + long 0x40040000,0xB6365E22,0xEE46F000,0xA1480000 + long 0x40040000,0xBC7EDCF7,0xFF523611,0x21E80000 + long 0x40040000,0xC2C75BCD,0x105D7C23,0x20D00000 + long 0x40040000,0xC90FDAA2,0x2168C235,0xA1800000 + + set INARG,FP_SCR0 + + set TWOTO63,L_SCR1 + set INT,L_SCR1 + set ENDFLAG,L_SCR2 + + global stan +stan: + fmov.x (%a0),%fp0 # LOAD INPUT + + mov.l (%a0),%d1 + mov.w 4(%a0),%d1 + and.l &0x7FFFFFFF,%d1 + + cmp.l %d1,&0x3FD78000 # |X| >= 2**(-40)? + bge.b TANOK1 + bra.w TANSM +TANOK1: + cmp.l %d1,&0x4004BC7E # |X| < 15 PI? + blt.b TANMAIN + bra.w REDUCEX + +TANMAIN: +#--THIS IS THE USUAL CASE, |X| <= 15 PI. +#--THE ARGUMENT REDUCTION IS DONE BY TABLE LOOK UP. + fmov.x %fp0,%fp1 + fmul.d TWOBYPI(%pc),%fp1 # X*2/PI + + lea.l PITBL+0x200(%pc),%a1 # TABLE OF N*PI/2, N = -32,...,32 + + fmov.l %fp1,%d1 # CONVERT TO INTEGER + + asl.l &4,%d1 + add.l %d1,%a1 # ADDRESS N*PIBY2 IN Y1, Y2 + + fsub.x (%a1)+,%fp0 # X-Y1 + + fsub.s (%a1),%fp0 # FP0 IS R = (X-Y1)-Y2 + + ror.l &5,%d1 + and.l &0x80000000,%d1 # D0 WAS ODD IFF D0 < 0 + +TANCONT: + fmovm.x &0x0c,-(%sp) # save fp2,fp3 + + cmp.l %d1,&0 + blt.w NODD + + fmov.x %fp0,%fp1 + fmul.x %fp1,%fp1 # S = R*R + + fmov.d TANQ4(%pc),%fp3 + fmov.d TANP3(%pc),%fp2 + + fmul.x %fp1,%fp3 # SQ4 + fmul.x %fp1,%fp2 # SP3 + + fadd.d TANQ3(%pc),%fp3 # Q3+SQ4 + fadd.x TANP2(%pc),%fp2 # P2+SP3 + + fmul.x %fp1,%fp3 # S(Q3+SQ4) + fmul.x %fp1,%fp2 # S(P2+SP3) + + fadd.x TANQ2(%pc),%fp3 # Q2+S(Q3+SQ4) + fadd.x TANP1(%pc),%fp2 # P1+S(P2+SP3) + + fmul.x %fp1,%fp3 # S(Q2+S(Q3+SQ4)) + fmul.x %fp1,%fp2 # S(P1+S(P2+SP3)) + + fadd.x TANQ1(%pc),%fp3 # Q1+S(Q2+S(Q3+SQ4)) + fmul.x %fp0,%fp2 # RS(P1+S(P2+SP3)) + + fmul.x %fp3,%fp1 # S(Q1+S(Q2+S(Q3+SQ4))) + + fadd.x %fp2,%fp0 # R+RS(P1+S(P2+SP3)) + + fadd.s &0x3F800000,%fp1 # 1+S(Q1+...) + + fmovm.x (%sp)+,&0x30 # restore fp2,fp3 + + fmov.l %d0,%fpcr # restore users round mode,prec + fdiv.x %fp1,%fp0 # last inst - possible exception set + bra t_inx2 + +NODD: + fmov.x %fp0,%fp1 + fmul.x %fp0,%fp0 # S = R*R + + fmov.d TANQ4(%pc),%fp3 + fmov.d TANP3(%pc),%fp2 + + fmul.x %fp0,%fp3 # SQ4 + fmul.x %fp0,%fp2 # SP3 + + fadd.d TANQ3(%pc),%fp3 # Q3+SQ4 + fadd.x TANP2(%pc),%fp2 # P2+SP3 + + fmul.x %fp0,%fp3 # S(Q3+SQ4) + fmul.x %fp0,%fp2 # S(P2+SP3) + + fadd.x TANQ2(%pc),%fp3 # Q2+S(Q3+SQ4) + fadd.x TANP1(%pc),%fp2 # P1+S(P2+SP3) + + fmul.x %fp0,%fp3 # S(Q2+S(Q3+SQ4)) + fmul.x %fp0,%fp2 # S(P1+S(P2+SP3)) + + fadd.x TANQ1(%pc),%fp3 # Q1+S(Q2+S(Q3+SQ4)) + fmul.x %fp1,%fp2 # RS(P1+S(P2+SP3)) + + fmul.x %fp3,%fp0 # S(Q1+S(Q2+S(Q3+SQ4))) + + fadd.x %fp2,%fp1 # R+RS(P1+S(P2+SP3)) + fadd.s &0x3F800000,%fp0 # 1+S(Q1+...) + + fmovm.x (%sp)+,&0x30 # restore fp2,fp3 + + fmov.x %fp1,-(%sp) + eor.l &0x80000000,(%sp) + + fmov.l %d0,%fpcr # restore users round mode,prec + fdiv.x (%sp)+,%fp0 # last inst - possible exception set + bra t_inx2 + +TANBORS: +#--IF |X| > 15PI, WE USE THE GENERAL ARGUMENT REDUCTION. +#--IF |X| < 2**(-40), RETURN X OR 1. + cmp.l %d1,&0x3FFF8000 + bgt.b REDUCEX + +TANSM: + fmov.x %fp0,-(%sp) + fmov.l %d0,%fpcr # restore users round mode,prec + mov.b &FMOV_OP,%d1 # last inst is MOVE + fmov.x (%sp)+,%fp0 # last inst - posibble exception set + bra t_catch + + global stand +#--TAN(X) = X FOR DENORMALIZED X +stand: + bra t_extdnrm + +#--WHEN REDUCEX IS USED, THE CODE WILL INEVITABLY BE SLOW. +#--THIS REDUCTION METHOD, HOWEVER, IS MUCH FASTER THAN USING +#--THE REMAINDER INSTRUCTION WHICH IS NOW IN SOFTWARE. +REDUCEX: + fmovm.x &0x3c,-(%sp) # save {fp2-fp5} + mov.l %d2,-(%sp) # save d2 + fmov.s &0x00000000,%fp1 # fp1 = 0 + +#--If compact form of abs(arg) in d0=$7ffeffff, argument is so large that +#--there is a danger of unwanted overflow in first LOOP iteration. In this +#--case, reduce argument by one remainder step to make subsequent reduction +#--safe. + cmp.l %d1,&0x7ffeffff # is arg dangerously large? + bne.b LOOP # no + +# yes; create 2**16383*PI/2 + mov.w &0x7ffe,FP_SCR0_EX(%a6) + mov.l &0xc90fdaa2,FP_SCR0_HI(%a6) + clr.l FP_SCR0_LO(%a6) + +# create low half of 2**16383*PI/2 at FP_SCR1 + mov.w &0x7fdc,FP_SCR1_EX(%a6) + mov.l &0x85a308d3,FP_SCR1_HI(%a6) + clr.l FP_SCR1_LO(%a6) + + ftest.x %fp0 # test sign of argument + fblt.w red_neg + + or.b &0x80,FP_SCR0_EX(%a6) # positive arg + or.b &0x80,FP_SCR1_EX(%a6) +red_neg: + fadd.x FP_SCR0(%a6),%fp0 # high part of reduction is exact + fmov.x %fp0,%fp1 # save high result in fp1 + fadd.x FP_SCR1(%a6),%fp0 # low part of reduction + fsub.x %fp0,%fp1 # determine low component of result + fadd.x FP_SCR1(%a6),%fp1 # fp0/fp1 are reduced argument. + +#--ON ENTRY, FP0 IS X, ON RETURN, FP0 IS X REM PI/2, |X| <= PI/4. +#--integer quotient will be stored in N +#--Intermeditate remainder is 66-bit long; (R,r) in (FP0,FP1) +LOOP: + fmov.x %fp0,INARG(%a6) # +-2**K * F, 1 <= F < 2 + mov.w INARG(%a6),%d1 + mov.l %d1,%a1 # save a copy of D0 + and.l &0x00007FFF,%d1 + sub.l &0x00003FFF,%d1 # d0 = K + cmp.l %d1,&28 + ble.b LASTLOOP +CONTLOOP: + sub.l &27,%d1 # d0 = L := K-27 + mov.b &0,ENDFLAG(%a6) + bra.b WORK +LASTLOOP: + clr.l %d1 # d0 = L := 0 + mov.b &1,ENDFLAG(%a6) + +WORK: +#--FIND THE REMAINDER OF (R,r) W.R.T. 2**L * (PI/2). L IS SO CHOSEN +#--THAT INT( X * (2/PI) / 2**(L) ) < 2**29. + +#--CREATE 2**(-L) * (2/PI), SIGN(INARG)*2**(63), +#--2**L * (PIby2_1), 2**L * (PIby2_2) + + mov.l &0x00003FFE,%d2 # BIASED EXP OF 2/PI + sub.l %d1,%d2 # BIASED EXP OF 2**(-L)*(2/PI) + + mov.l &0xA2F9836E,FP_SCR0_HI(%a6) + mov.l &0x4E44152A,FP_SCR0_LO(%a6) + mov.w %d2,FP_SCR0_EX(%a6) # FP_SCR0 = 2**(-L)*(2/PI) + + fmov.x %fp0,%fp2 + fmul.x FP_SCR0(%a6),%fp2 # fp2 = X * 2**(-L)*(2/PI) + +#--WE MUST NOW FIND INT(FP2). SINCE WE NEED THIS VALUE IN +#--FLOATING POINT FORMAT, THE TWO FMOVE'S FMOVE.L FP <--> N +#--WILL BE TOO INEFFICIENT. THE WAY AROUND IT IS THAT +#--(SIGN(INARG)*2**63 + FP2) - SIGN(INARG)*2**63 WILL GIVE +#--US THE DESIRED VALUE IN FLOATING POINT. + mov.l %a1,%d2 + swap %d2 + and.l &0x80000000,%d2 + or.l &0x5F000000,%d2 # d2 = SIGN(INARG)*2**63 IN SGL + mov.l %d2,TWOTO63(%a6) + fadd.s TWOTO63(%a6),%fp2 # THE FRACTIONAL PART OF FP1 IS ROUNDED + fsub.s TWOTO63(%a6),%fp2 # fp2 = N +# fintrz.x %fp2,%fp2 + +#--CREATING 2**(L)*Piby2_1 and 2**(L)*Piby2_2 + mov.l %d1,%d2 # d2 = L + + add.l &0x00003FFF,%d2 # BIASED EXP OF 2**L * (PI/2) + mov.w %d2,FP_SCR0_EX(%a6) + mov.l &0xC90FDAA2,FP_SCR0_HI(%a6) + clr.l FP_SCR0_LO(%a6) # FP_SCR0 = 2**(L) * Piby2_1 + + add.l &0x00003FDD,%d1 + mov.w %d1,FP_SCR1_EX(%a6) + mov.l &0x85A308D3,FP_SCR1_HI(%a6) + clr.l FP_SCR1_LO(%a6) # FP_SCR1 = 2**(L) * Piby2_2 + + mov.b ENDFLAG(%a6),%d1 + +#--We are now ready to perform (R+r) - N*P1 - N*P2, P1 = 2**(L) * Piby2_1 and +#--P2 = 2**(L) * Piby2_2 + fmov.x %fp2,%fp4 # fp4 = N + fmul.x FP_SCR0(%a6),%fp4 # fp4 = W = N*P1 + fmov.x %fp2,%fp5 # fp5 = N + fmul.x FP_SCR1(%a6),%fp5 # fp5 = w = N*P2 + fmov.x %fp4,%fp3 # fp3 = W = N*P1 + +#--we want P+p = W+w but |p| <= half ulp of P +#--Then, we need to compute A := R-P and a := r-p + fadd.x %fp5,%fp3 # fp3 = P + fsub.x %fp3,%fp4 # fp4 = W-P + + fsub.x %fp3,%fp0 # fp0 = A := R - P + fadd.x %fp5,%fp4 # fp4 = p = (W-P)+w + + fmov.x %fp0,%fp3 # fp3 = A + fsub.x %fp4,%fp1 # fp1 = a := r - p + +#--Now we need to normalize (A,a) to "new (R,r)" where R+r = A+a but +#--|r| <= half ulp of R. + fadd.x %fp1,%fp0 # fp0 = R := A+a +#--No need to calculate r if this is the last loop + cmp.b %d1,&0 + bgt.w RESTORE + +#--Need to calculate r + fsub.x %fp0,%fp3 # fp3 = A-R + fadd.x %fp3,%fp1 # fp1 = r := (A-R)+a + bra.w LOOP + +RESTORE: + fmov.l %fp2,INT(%a6) + mov.l (%sp)+,%d2 # restore d2 + fmovm.x (%sp)+,&0x3c # restore {fp2-fp5} + + mov.l INT(%a6),%d1 + ror.l &1,%d1 + + bra.w TANCONT + +######################################################################### +# satan(): computes the arctangent of a normalized number # +# satand(): computes the arctangent of a denormalized number # +# # +# INPUT *************************************************************** # +# a0 = pointer to extended precision input # +# d0 = round precision,mode # +# # +# OUTPUT ************************************************************** # +# fp0 = arctan(X) # +# # +# ACCURACY and MONOTONICITY ******************************************* # +# The returned result is within 2 ulps in 64 significant bit, # +# i.e. within 0.5001 ulp to 53 bits if the result is subsequently # +# rounded to double precision. The result is provably monotonic # +# in double precision. # +# # +# ALGORITHM *********************************************************** # +# Step 1. If |X| >= 16 or |X| < 1/16, go to Step 5. # +# # +# Step 2. Let X = sgn * 2**k * 1.xxxxxxxx...x. # +# Note that k = -4, -3,..., or 3. # +# Define F = sgn * 2**k * 1.xxxx1, i.e. the first 5 # +# significant bits of X with a bit-1 attached at the 6-th # +# bit position. Define u to be u = (X-F) / (1 + X*F). # +# # +# Step 3. Approximate arctan(u) by a polynomial poly. # +# # +# Step 4. Return arctan(F) + poly, arctan(F) is fetched from a # +# table of values calculated beforehand. Exit. # +# # +# Step 5. If |X| >= 16, go to Step 7. # +# # +# Step 6. Approximate arctan(X) by an odd polynomial in X. Exit. # +# # +# Step 7. Define X' = -1/X. Approximate arctan(X') by an odd # +# polynomial in X'. # +# Arctan(X) = sign(X)*Pi/2 + arctan(X'). Exit. # +# # +######################################################################### + +ATANA3: long 0xBFF6687E,0x314987D8 +ATANA2: long 0x4002AC69,0x34A26DB3 +ATANA1: long 0xBFC2476F,0x4E1DA28E + +ATANB6: long 0x3FB34444,0x7F876989 +ATANB5: long 0xBFB744EE,0x7FAF45DB +ATANB4: long 0x3FBC71C6,0x46940220 +ATANB3: long 0xBFC24924,0x921872F9 +ATANB2: long 0x3FC99999,0x99998FA9 +ATANB1: long 0xBFD55555,0x55555555 + +ATANC5: long 0xBFB70BF3,0x98539E6A +ATANC4: long 0x3FBC7187,0x962D1D7D +ATANC3: long 0xBFC24924,0x827107B8 +ATANC2: long 0x3FC99999,0x9996263E +ATANC1: long 0xBFD55555,0x55555536 + +PPIBY2: long 0x3FFF0000,0xC90FDAA2,0x2168C235,0x00000000 +NPIBY2: long 0xBFFF0000,0xC90FDAA2,0x2168C235,0x00000000 + +PTINY: long 0x00010000,0x80000000,0x00000000,0x00000000 +NTINY: long 0x80010000,0x80000000,0x00000000,0x00000000 + +ATANTBL: + long 0x3FFB0000,0x83D152C5,0x060B7A51,0x00000000 + long 0x3FFB0000,0x8BC85445,0x65498B8B,0x00000000 + long 0x3FFB0000,0x93BE4060,0x17626B0D,0x00000000 + long 0x3FFB0000,0x9BB3078D,0x35AEC202,0x00000000 + long 0x3FFB0000,0xA3A69A52,0x5DDCE7DE,0x00000000 + long 0x3FFB0000,0xAB98E943,0x62765619,0x00000000 + long 0x3FFB0000,0xB389E502,0xF9C59862,0x00000000 + long 0x3FFB0000,0xBB797E43,0x6B09E6FB,0x00000000 + long 0x3FFB0000,0xC367A5C7,0x39E5F446,0x00000000 + long 0x3FFB0000,0xCB544C61,0xCFF7D5C6,0x00000000 + long 0x3FFB0000,0xD33F62F8,0x2488533E,0x00000000 + long 0x3FFB0000,0xDB28DA81,0x62404C77,0x00000000 + long 0x3FFB0000,0xE310A407,0x8AD34F18,0x00000000 + long 0x3FFB0000,0xEAF6B0A8,0x188EE1EB,0x00000000 + long 0x3FFB0000,0xF2DAF194,0x9DBE79D5,0x00000000 + long 0x3FFB0000,0xFABD5813,0x61D47E3E,0x00000000 + long 0x3FFC0000,0x8346AC21,0x0959ECC4,0x00000000 + long 0x3FFC0000,0x8B232A08,0x304282D8,0x00000000 + long 0x3FFC0000,0x92FB70B8,0xD29AE2F9,0x00000000 + long 0x3FFC0000,0x9ACF476F,0x5CCD1CB4,0x00000000 + long 0x3FFC0000,0xA29E7630,0x4954F23F,0x00000000 + long 0x3FFC0000,0xAA68C5D0,0x8AB85230,0x00000000 + long 0x3FFC0000,0xB22DFFFD,0x9D539F83,0x00000000 + long 0x3FFC0000,0xB9EDEF45,0x3E900EA5,0x00000000 + long 0x3FFC0000,0xC1A85F1C,0xC75E3EA5,0x00000000 + long 0x3FFC0000,0xC95D1BE8,0x28138DE6,0x00000000 + long 0x3FFC0000,0xD10BF300,0x840D2DE4,0x00000000 + long 0x3FFC0000,0xD8B4B2BA,0x6BC05E7A,0x00000000 + long 0x3FFC0000,0xE0572A6B,0xB42335F6,0x00000000 + long 0x3FFC0000,0xE7F32A70,0xEA9CAA8F,0x00000000 + long 0x3FFC0000,0xEF888432,0x64ECEFAA,0x00000000 + long 0x3FFC0000,0xF7170A28,0xECC06666,0x00000000 + long 0x3FFD0000,0x812FD288,0x332DAD32,0x00000000 + long 0x3FFD0000,0x88A8D1B1,0x218E4D64,0x00000000 + long 0x3FFD0000,0x9012AB3F,0x23E4AEE8,0x00000000 + long 0x3FFD0000,0x976CC3D4,0x11E7F1B9,0x00000000 + long 0x3FFD0000,0x9EB68949,0x3889A227,0x00000000 + long 0x3FFD0000,0xA5EF72C3,0x4487361B,0x00000000 + long 0x3FFD0000,0xAD1700BA,0xF07A7227,0x00000000 + long 0x3FFD0000,0xB42CBCFA,0xFD37EFB7,0x00000000 + long 0x3FFD0000,0xBB303A94,0x0BA80F89,0x00000000 + long 0x3FFD0000,0xC22115C6,0xFCAEBBAF,0x00000000 + long 0x3FFD0000,0xC8FEF3E6,0x86331221,0x00000000 + long 0x3FFD0000,0xCFC98330,0xB4000C70,0x00000000 + long 0x3FFD0000,0xD6807AA1,0x102C5BF9,0x00000000 + long 0x3FFD0000,0xDD2399BC,0x31252AA3,0x00000000 + long 0x3FFD0000,0xE3B2A855,0x6B8FC517,0x00000000 + long 0x3FFD0000,0xEA2D764F,0x64315989,0x00000000 + long 0x3FFD0000,0xF3BF5BF8,0xBAD1A21D,0x00000000 + long 0x3FFE0000,0x801CE39E,0x0D205C9A,0x00000000 + long 0x3FFE0000,0x8630A2DA,0xDA1ED066,0x00000000 + long 0x3FFE0000,0x8C1AD445,0xF3E09B8C,0x00000000 + long 0x3FFE0000,0x91DB8F16,0x64F350E2,0x00000000 + long 0x3FFE0000,0x97731420,0x365E538C,0x00000000 + long 0x3FFE0000,0x9CE1C8E6,0xA0B8CDBA,0x00000000 + long 0x3FFE0000,0xA22832DB,0xCADAAE09,0x00000000 + long 0x3FFE0000,0xA746F2DD,0xB7602294,0x00000000 + long 0x3FFE0000,0xAC3EC0FB,0x997DD6A2,0x00000000 + long 0x3FFE0000,0xB110688A,0xEBDC6F6A,0x00000000 + long 0x3FFE0000,0xB5BCC490,0x59ECC4B0,0x00000000 + long 0x3FFE0000,0xBA44BC7D,0xD470782F,0x00000000 + long 0x3FFE0000,0xBEA94144,0xFD049AAC,0x00000000 + long 0x3FFE0000,0xC2EB4ABB,0x661628B6,0x00000000 + long 0x3FFE0000,0xC70BD54C,0xE602EE14,0x00000000 + long 0x3FFE0000,0xCD000549,0xADEC7159,0x00000000 + long 0x3FFE0000,0xD48457D2,0xD8EA4EA3,0x00000000 + long 0x3FFE0000,0xDB948DA7,0x12DECE3B,0x00000000 + long 0x3FFE0000,0xE23855F9,0x69E8096A,0x00000000 + long 0x3FFE0000,0xE8771129,0xC4353259,0x00000000 + long 0x3FFE0000,0xEE57C16E,0x0D379C0D,0x00000000 + long 0x3FFE0000,0xF3E10211,0xA87C3779,0x00000000 + long 0x3FFE0000,0xF919039D,0x758B8D41,0x00000000 + long 0x3FFE0000,0xFE058B8F,0x64935FB3,0x00000000 + long 0x3FFF0000,0x8155FB49,0x7B685D04,0x00000000 + long 0x3FFF0000,0x83889E35,0x49D108E1,0x00000000 + long 0x3FFF0000,0x859CFA76,0x511D724B,0x00000000 + long 0x3FFF0000,0x87952ECF,0xFF8131E7,0x00000000 + long 0x3FFF0000,0x89732FD1,0x9557641B,0x00000000 + long 0x3FFF0000,0x8B38CAD1,0x01932A35,0x00000000 + long 0x3FFF0000,0x8CE7A8D8,0x301EE6B5,0x00000000 + long 0x3FFF0000,0x8F46A39E,0x2EAE5281,0x00000000 + long 0x3FFF0000,0x922DA7D7,0x91888487,0x00000000 + long 0x3FFF0000,0x94D19FCB,0xDEDF5241,0x00000000 + long 0x3FFF0000,0x973AB944,0x19D2A08B,0x00000000 + long 0x3FFF0000,0x996FF00E,0x08E10B96,0x00000000 + long 0x3FFF0000,0x9B773F95,0x12321DA7,0x00000000 + long 0x3FFF0000,0x9D55CC32,0x0F935624,0x00000000 + long 0x3FFF0000,0x9F100575,0x006CC571,0x00000000 + long 0x3FFF0000,0xA0A9C290,0xD97CC06C,0x00000000 + long 0x3FFF0000,0xA22659EB,0xEBC0630A,0x00000000 + long 0x3FFF0000,0xA388B4AF,0xF6EF0EC9,0x00000000 + long 0x3FFF0000,0xA4D35F10,0x61D292C4,0x00000000 + long 0x3FFF0000,0xA60895DC,0xFBE3187E,0x00000000 + long 0x3FFF0000,0xA72A51DC,0x7367BEAC,0x00000000 + long 0x3FFF0000,0xA83A5153,0x0956168F,0x00000000 + long 0x3FFF0000,0xA93A2007,0x7539546E,0x00000000 + long 0x3FFF0000,0xAA9E7245,0x023B2605,0x00000000 + long 0x3FFF0000,0xAC4C84BA,0x6FE4D58F,0x00000000 + long 0x3FFF0000,0xADCE4A4A,0x606B9712,0x00000000 + long 0x3FFF0000,0xAF2A2DCD,0x8D263C9C,0x00000000 + long 0x3FFF0000,0xB0656F81,0xF22265C7,0x00000000 + long 0x3FFF0000,0xB1846515,0x0F71496A,0x00000000 + long 0x3FFF0000,0xB28AAA15,0x6F9ADA35,0x00000000 + long 0x3FFF0000,0xB37B44FF,0x3766B895,0x00000000 + long 0x3FFF0000,0xB458C3DC,0xE9630433,0x00000000 + long 0x3FFF0000,0xB525529D,0x562246BD,0x00000000 + long 0x3FFF0000,0xB5E2CCA9,0x5F9D88CC,0x00000000 + long 0x3FFF0000,0xB692CADA,0x7ACA1ADA,0x00000000 + long 0x3FFF0000,0xB736AEA7,0xA6925838,0x00000000 + long 0x3FFF0000,0xB7CFAB28,0x7E9F7B36,0x00000000 + long 0x3FFF0000,0xB85ECC66,0xCB219835,0x00000000 + long 0x3FFF0000,0xB8E4FD5A,0x20A593DA,0x00000000 + long 0x3FFF0000,0xB99F41F6,0x4AFF9BB5,0x00000000 + long 0x3FFF0000,0xBA7F1E17,0x842BBE7B,0x00000000 + long 0x3FFF0000,0xBB471285,0x7637E17D,0x00000000 + long 0x3FFF0000,0xBBFABE8A,0x4788DF6F,0x00000000 + long 0x3FFF0000,0xBC9D0FAD,0x2B689D79,0x00000000 + long 0x3FFF0000,0xBD306A39,0x471ECD86,0x00000000 + long 0x3FFF0000,0xBDB6C731,0x856AF18A,0x00000000 + long 0x3FFF0000,0xBE31CAC5,0x02E80D70,0x00000000 + long 0x3FFF0000,0xBEA2D55C,0xE33194E2,0x00000000 + long 0x3FFF0000,0xBF0B10B7,0xC03128F0,0x00000000 + long 0x3FFF0000,0xBF6B7A18,0xDACB778D,0x00000000 + long 0x3FFF0000,0xBFC4EA46,0x63FA18F6,0x00000000 + long 0x3FFF0000,0xC0181BDE,0x8B89A454,0x00000000 + long 0x3FFF0000,0xC065B066,0xCFBF6439,0x00000000 + long 0x3FFF0000,0xC0AE345F,0x56340AE6,0x00000000 + long 0x3FFF0000,0xC0F22291,0x9CB9E6A7,0x00000000 + + set X,FP_SCR0 + set XDCARE,X+2 + set XFRAC,X+4 + set XFRACLO,X+8 + + set ATANF,FP_SCR1 + set ATANFHI,ATANF+4 + set ATANFLO,ATANF+8 + + global satan +#--ENTRY POINT FOR ATAN(X), HERE X IS FINITE, NON-ZERO, AND NOT NAN'S +satan: + fmov.x (%a0),%fp0 # LOAD INPUT + + mov.l (%a0),%d1 + mov.w 4(%a0),%d1 + fmov.x %fp0,X(%a6) + and.l &0x7FFFFFFF,%d1 + + cmp.l %d1,&0x3FFB8000 # |X| >= 1/16? + bge.b ATANOK1 + bra.w ATANSM + +ATANOK1: + cmp.l %d1,&0x4002FFFF # |X| < 16 ? + ble.b ATANMAIN + bra.w ATANBIG + +#--THE MOST LIKELY CASE, |X| IN [1/16, 16). WE USE TABLE TECHNIQUE +#--THE IDEA IS ATAN(X) = ATAN(F) + ATAN( [X-F] / [1+XF] ). +#--SO IF F IS CHOSEN TO BE CLOSE TO X AND ATAN(F) IS STORED IN +#--A TABLE, ALL WE NEED IS TO APPROXIMATE ATAN(U) WHERE +#--U = (X-F)/(1+XF) IS SMALL (REMEMBER F IS CLOSE TO X). IT IS +#--TRUE THAT A DIVIDE IS NOW NEEDED, BUT THE APPROXIMATION FOR +#--ATAN(U) IS A VERY SHORT POLYNOMIAL AND THE INDEXING TO +#--FETCH F AND SAVING OF REGISTERS CAN BE ALL HIDED UNDER THE +#--DIVIDE. IN THE END THIS METHOD IS MUCH FASTER THAN A TRADITIONAL +#--ONE. NOTE ALSO THAT THE TRADITIONAL SCHEME THAT APPROXIMATE +#--ATAN(X) DIRECTLY WILL NEED TO USE A RATIONAL APPROXIMATION +#--(DIVISION NEEDED) ANYWAY BECAUSE A POLYNOMIAL APPROXIMATION +#--WILL INVOLVE A VERY LONG POLYNOMIAL. + +#--NOW WE SEE X AS +-2^K * 1.BBBBBBB....B <- 1. + 63 BITS +#--WE CHOSE F TO BE +-2^K * 1.BBBB1 +#--THAT IS IT MATCHES THE EXPONENT AND FIRST 5 BITS OF X, THE +#--SIXTH BITS IS SET TO BE 1. SINCE K = -4, -3, ..., 3, THERE +#--ARE ONLY 8 TIMES 16 = 2^7 = 128 |F|'S. SINCE ATAN(-|F|) IS +#-- -ATAN(|F|), WE NEED TO STORE ONLY ATAN(|F|). + +ATANMAIN: + + and.l &0xF8000000,XFRAC(%a6) # FIRST 5 BITS + or.l &0x04000000,XFRAC(%a6) # SET 6-TH BIT TO 1 + mov.l &0x00000000,XFRACLO(%a6) # LOCATION OF X IS NOW F + + fmov.x %fp0,%fp1 # FP1 IS X + fmul.x X(%a6),%fp1 # FP1 IS X*F, NOTE THAT X*F > 0 + fsub.x X(%a6),%fp0 # FP0 IS X-F + fadd.s &0x3F800000,%fp1 # FP1 IS 1 + X*F + fdiv.x %fp1,%fp0 # FP0 IS U = (X-F)/(1+X*F) + +#--WHILE THE DIVISION IS TAKING ITS TIME, WE FETCH ATAN(|F|) +#--CREATE ATAN(F) AND STORE IT IN ATANF, AND +#--SAVE REGISTERS FP2. + + mov.l %d2,-(%sp) # SAVE d2 TEMPORARILY + mov.l %d1,%d2 # THE EXP AND 16 BITS OF X + and.l &0x00007800,%d1 # 4 VARYING BITS OF F'S FRACTION + and.l &0x7FFF0000,%d2 # EXPONENT OF F + sub.l &0x3FFB0000,%d2 # K+4 + asr.l &1,%d2 + add.l %d2,%d1 # THE 7 BITS IDENTIFYING F + asr.l &7,%d1 # INDEX INTO TBL OF ATAN(|F|) + lea ATANTBL(%pc),%a1 + add.l %d1,%a1 # ADDRESS OF ATAN(|F|) + mov.l (%a1)+,ATANF(%a6) + mov.l (%a1)+,ATANFHI(%a6) + mov.l (%a1)+,ATANFLO(%a6) # ATANF IS NOW ATAN(|F|) + mov.l X(%a6),%d1 # LOAD SIGN AND EXPO. AGAIN + and.l &0x80000000,%d1 # SIGN(F) + or.l %d1,ATANF(%a6) # ATANF IS NOW SIGN(F)*ATAN(|F|) + mov.l (%sp)+,%d2 # RESTORE d2 + +#--THAT'S ALL I HAVE TO DO FOR NOW, +#--BUT ALAS, THE DIVIDE IS STILL CRANKING! + +#--U IN FP0, WE ARE NOW READY TO COMPUTE ATAN(U) AS +#--U + A1*U*V*(A2 + V*(A3 + V)), V = U*U +#--THE POLYNOMIAL MAY LOOK STRANGE, BUT IS NEVERTHELESS CORRECT. +#--THE NATURAL FORM IS U + U*V*(A1 + V*(A2 + V*A3)) +#--WHAT WE HAVE HERE IS MERELY A1 = A3, A2 = A1/A3, A3 = A2/A3. +#--THE REASON FOR THIS REARRANGEMENT IS TO MAKE THE INDEPENDENT +#--PARTS A1*U*V AND (A2 + ... STUFF) MORE LOAD-BALANCED + + fmovm.x &0x04,-(%sp) # save fp2 + + fmov.x %fp0,%fp1 + fmul.x %fp1,%fp1 + fmov.d ATANA3(%pc),%fp2 + fadd.x %fp1,%fp2 # A3+V + fmul.x %fp1,%fp2 # V*(A3+V) + fmul.x %fp0,%fp1 # U*V + fadd.d ATANA2(%pc),%fp2 # A2+V*(A3+V) + fmul.d ATANA1(%pc),%fp1 # A1*U*V + fmul.x %fp2,%fp1 # A1*U*V*(A2+V*(A3+V)) + fadd.x %fp1,%fp0 # ATAN(U), FP1 RELEASED + + fmovm.x (%sp)+,&0x20 # restore fp2 + + fmov.l %d0,%fpcr # restore users rnd mode,prec + fadd.x ATANF(%a6),%fp0 # ATAN(X) + bra t_inx2 + +ATANBORS: +#--|X| IS IN d0 IN COMPACT FORM. FP1, d0 SAVED. +#--FP0 IS X AND |X| <= 1/16 OR |X| >= 16. + cmp.l %d1,&0x3FFF8000 + bgt.w ATANBIG # I.E. |X| >= 16 + +ATANSM: +#--|X| <= 1/16 +#--IF |X| < 2^(-40), RETURN X AS ANSWER. OTHERWISE, APPROXIMATE +#--ATAN(X) BY X + X*Y*(B1+Y*(B2+Y*(B3+Y*(B4+Y*(B5+Y*B6))))) +#--WHICH IS X + X*Y*( [B1+Z*(B3+Z*B5)] + [Y*(B2+Z*(B4+Z*B6)] ) +#--WHERE Y = X*X, AND Z = Y*Y. + + cmp.l %d1,&0x3FD78000 + blt.w ATANTINY + +#--COMPUTE POLYNOMIAL + fmovm.x &0x0c,-(%sp) # save fp2/fp3 + + fmul.x %fp0,%fp0 # FPO IS Y = X*X + + fmov.x %fp0,%fp1 + fmul.x %fp1,%fp1 # FP1 IS Z = Y*Y + + fmov.d ATANB6(%pc),%fp2 + fmov.d ATANB5(%pc),%fp3 + + fmul.x %fp1,%fp2 # Z*B6 + fmul.x %fp1,%fp3 # Z*B5 + + fadd.d ATANB4(%pc),%fp2 # B4+Z*B6 + fadd.d ATANB3(%pc),%fp3 # B3+Z*B5 + + fmul.x %fp1,%fp2 # Z*(B4+Z*B6) + fmul.x %fp3,%fp1 # Z*(B3+Z*B5) + + fadd.d ATANB2(%pc),%fp2 # B2+Z*(B4+Z*B6) + fadd.d ATANB1(%pc),%fp1 # B1+Z*(B3+Z*B5) + + fmul.x %fp0,%fp2 # Y*(B2+Z*(B4+Z*B6)) + fmul.x X(%a6),%fp0 # X*Y + + fadd.x %fp2,%fp1 # [B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))] + + fmul.x %fp1,%fp0 # X*Y*([B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))]) + + fmovm.x (%sp)+,&0x30 # restore fp2/fp3 + + fmov.l %d0,%fpcr # restore users rnd mode,prec + fadd.x X(%a6),%fp0 + bra t_inx2 + +ATANTINY: +#--|X| < 2^(-40), ATAN(X) = X + + fmov.l %d0,%fpcr # restore users rnd mode,prec + mov.b &FMOV_OP,%d1 # last inst is MOVE + fmov.x X(%a6),%fp0 # last inst - possible exception set + + bra t_catch + +ATANBIG: +#--IF |X| > 2^(100), RETURN SIGN(X)*(PI/2 - TINY). OTHERWISE, +#--RETURN SIGN(X)*PI/2 + ATAN(-1/X). + cmp.l %d1,&0x40638000 + bgt.w ATANHUGE + +#--APPROXIMATE ATAN(-1/X) BY +#--X'+X'*Y*(C1+Y*(C2+Y*(C3+Y*(C4+Y*C5)))), X' = -1/X, Y = X'*X' +#--THIS CAN BE RE-WRITTEN AS +#--X'+X'*Y*( [C1+Z*(C3+Z*C5)] + [Y*(C2+Z*C4)] ), Z = Y*Y. + + fmovm.x &0x0c,-(%sp) # save fp2/fp3 + + fmov.s &0xBF800000,%fp1 # LOAD -1 + fdiv.x %fp0,%fp1 # FP1 IS -1/X + +#--DIVIDE IS STILL CRANKING + + fmov.x %fp1,%fp0 # FP0 IS X' + fmul.x %fp0,%fp0 # FP0 IS Y = X'*X' + fmov.x %fp1,X(%a6) # X IS REALLY X' + + fmov.x %fp0,%fp1 + fmul.x %fp1,%fp1 # FP1 IS Z = Y*Y + + fmov.d ATANC5(%pc),%fp3 + fmov.d ATANC4(%pc),%fp2 + + fmul.x %fp1,%fp3 # Z*C5 + fmul.x %fp1,%fp2 # Z*B4 + + fadd.d ATANC3(%pc),%fp3 # C3+Z*C5 + fadd.d ATANC2(%pc),%fp2 # C2+Z*C4 + + fmul.x %fp3,%fp1 # Z*(C3+Z*C5), FP3 RELEASED + fmul.x %fp0,%fp2 # Y*(C2+Z*C4) + + fadd.d ATANC1(%pc),%fp1 # C1+Z*(C3+Z*C5) + fmul.x X(%a6),%fp0 # X'*Y + + fadd.x %fp2,%fp1 # [Y*(C2+Z*C4)]+[C1+Z*(C3+Z*C5)] + + fmul.x %fp1,%fp0 # X'*Y*([B1+Z*(B3+Z*B5)] +# ... +[Y*(B2+Z*(B4+Z*B6))]) + fadd.x X(%a6),%fp0 + + fmovm.x (%sp)+,&0x30 # restore fp2/fp3 + + fmov.l %d0,%fpcr # restore users rnd mode,prec + tst.b (%a0) + bpl.b pos_big + +neg_big: + fadd.x NPIBY2(%pc),%fp0 + bra t_minx2 + +pos_big: + fadd.x PPIBY2(%pc),%fp0 + bra t_pinx2 + +ATANHUGE: +#--RETURN SIGN(X)*(PIBY2 - TINY) = SIGN(X)*PIBY2 - SIGN(X)*TINY + tst.b (%a0) + bpl.b pos_huge + +neg_huge: + fmov.x NPIBY2(%pc),%fp0 + fmov.l %d0,%fpcr + fadd.x PTINY(%pc),%fp0 + bra t_minx2 + +pos_huge: + fmov.x PPIBY2(%pc),%fp0 + fmov.l %d0,%fpcr + fadd.x NTINY(%pc),%fp0 + bra t_pinx2 + + global satand +#--ENTRY POINT FOR ATAN(X) FOR DENORMALIZED ARGUMENT +satand: + bra t_extdnrm + +######################################################################### +# sasin(): computes the inverse sine of a normalized input # +# sasind(): computes the inverse sine of a denormalized input # +# # +# INPUT *************************************************************** # +# a0 = pointer to extended precision input # +# d0 = round precision,mode # +# # +# OUTPUT ************************************************************** # +# fp0 = arcsin(X) # +# # +# ACCURACY and MONOTONICITY ******************************************* # +# The returned result is within 3 ulps in 64 significant bit, # +# i.e. within 0.5001 ulp to 53 bits if the result is subsequently # +# rounded to double precision. The result is provably monotonic # +# in double precision. # +# # +# ALGORITHM *********************************************************** # +# # +# ASIN # +# 1. If |X| >= 1, go to 3. # +# # +# 2. (|X| < 1) Calculate asin(X) by # +# z := sqrt( [1-X][1+X] ) # +# asin(X) = atan( x / z ). # +# Exit. # +# # +# 3. If |X| > 1, go to 5. # +# # +# 4. (|X| = 1) sgn := sign(X), return asin(X) := sgn * Pi/2. Exit.# +# # +# 5. (|X| > 1) Generate an invalid operation by 0 * infinity. # +# Exit. # +# # +######################################################################### + + global sasin +sasin: + fmov.x (%a0),%fp0 # LOAD INPUT + + mov.l (%a0),%d1 + mov.w 4(%a0),%d1 + and.l &0x7FFFFFFF,%d1 + cmp.l %d1,&0x3FFF8000 + bge.b ASINBIG + +# This catch is added here for the '060 QSP. Originally, the call to +# satan() would handle this case by causing the exception which would +# not be caught until gen_except(). Now, with the exceptions being +# detected inside of satan(), the exception would have been handled there +# instead of inside sasin() as expected. + cmp.l %d1,&0x3FD78000 + blt.w ASINTINY + +#--THIS IS THE USUAL CASE, |X| < 1 +#--ASIN(X) = ATAN( X / SQRT( (1-X)(1+X) ) ) + +ASINMAIN: + fmov.s &0x3F800000,%fp1 + fsub.x %fp0,%fp1 # 1-X + fmovm.x &0x4,-(%sp) # {fp2} + fmov.s &0x3F800000,%fp2 + fadd.x %fp0,%fp2 # 1+X + fmul.x %fp2,%fp1 # (1+X)(1-X) + fmovm.x (%sp)+,&0x20 # {fp2} + fsqrt.x %fp1 # SQRT([1-X][1+X]) + fdiv.x %fp1,%fp0 # X/SQRT([1-X][1+X]) + fmovm.x &0x01,-(%sp) # save X/SQRT(...) + lea (%sp),%a0 # pass ptr to X/SQRT(...) + bsr satan + add.l &0xc,%sp # clear X/SQRT(...) from stack + bra t_inx2 + +ASINBIG: + fabs.x %fp0 # |X| + fcmp.s %fp0,&0x3F800000 + fbgt t_operr # cause an operr exception + +#--|X| = 1, ASIN(X) = +- PI/2. +ASINONE: + fmov.x PIBY2(%pc),%fp0 + mov.l (%a0),%d1 + and.l &0x80000000,%d1 # SIGN BIT OF X + or.l &0x3F800000,%d1 # +-1 IN SGL FORMAT + mov.l %d1,-(%sp) # push SIGN(X) IN SGL-FMT + fmov.l %d0,%fpcr + fmul.s (%sp)+,%fp0 + bra t_inx2 + +#--|X| < 2^(-40), ATAN(X) = X +ASINTINY: + fmov.l %d0,%fpcr # restore users rnd mode,prec + mov.b &FMOV_OP,%d1 # last inst is MOVE + fmov.x (%a0),%fp0 # last inst - possible exception + bra t_catch + + global sasind +#--ASIN(X) = X FOR DENORMALIZED X +sasind: + bra t_extdnrm + +######################################################################### +# sacos(): computes the inverse cosine of a normalized input # +# sacosd(): computes the inverse cosine of a denormalized input # +# # +# INPUT *************************************************************** # +# a0 = pointer to extended precision input # +# d0 = round precision,mode # +# # +# OUTPUT ************************************************************** # +# fp0 = arccos(X) # +# # +# ACCURACY and MONOTONICITY ******************************************* # +# The returned result is within 3 ulps in 64 significant bit, # +# i.e. within 0.5001 ulp to 53 bits if the result is subsequently # +# rounded to double precision. The result is provably monotonic # +# in double precision. # +# # +# ALGORITHM *********************************************************** # +# # +# ACOS # +# 1. If |X| >= 1, go to 3. # +# # +# 2. (|X| < 1) Calculate acos(X) by # +# z := (1-X) / (1+X) # +# acos(X) = 2 * atan( sqrt(z) ). # +# Exit. # +# # +# 3. If |X| > 1, go to 5. # +# # +# 4. (|X| = 1) If X > 0, return 0. Otherwise, return Pi. Exit. # +# # +# 5. (|X| > 1) Generate an invalid operation by 0 * infinity. # +# Exit. # +# # +######################################################################### + + global sacos +sacos: + fmov.x (%a0),%fp0 # LOAD INPUT + + mov.l (%a0),%d1 # pack exp w/ upper 16 fraction + mov.w 4(%a0),%d1 + and.l &0x7FFFFFFF,%d1 + cmp.l %d1,&0x3FFF8000 + bge.b ACOSBIG + +#--THIS IS THE USUAL CASE, |X| < 1 +#--ACOS(X) = 2 * ATAN( SQRT( (1-X)/(1+X) ) ) + +ACOSMAIN: + fmov.s &0x3F800000,%fp1 + fadd.x %fp0,%fp1 # 1+X + fneg.x %fp0 # -X + fadd.s &0x3F800000,%fp0 # 1-X + fdiv.x %fp1,%fp0 # (1-X)/(1+X) + fsqrt.x %fp0 # SQRT((1-X)/(1+X)) + mov.l %d0,-(%sp) # save original users fpcr + clr.l %d0 + fmovm.x &0x01,-(%sp) # save SQRT(...) to stack + lea (%sp),%a0 # pass ptr to sqrt + bsr satan # ATAN(SQRT([1-X]/[1+X])) + add.l &0xc,%sp # clear SQRT(...) from stack + + fmov.l (%sp)+,%fpcr # restore users round prec,mode + fadd.x %fp0,%fp0 # 2 * ATAN( STUFF ) + bra t_pinx2 + +ACOSBIG: + fabs.x %fp0 + fcmp.s %fp0,&0x3F800000 + fbgt t_operr # cause an operr exception + +#--|X| = 1, ACOS(X) = 0 OR PI + tst.b (%a0) # is X positive or negative? + bpl.b ACOSP1 + +#--X = -1 +#Returns PI and inexact exception +ACOSM1: + fmov.x PI(%pc),%fp0 # load PI + fmov.l %d0,%fpcr # load round mode,prec + fadd.s &0x00800000,%fp0 # add a small value + bra t_pinx2 + +ACOSP1: + bra ld_pzero # answer is positive zero + + global sacosd +#--ACOS(X) = PI/2 FOR DENORMALIZED X +sacosd: + fmov.l %d0,%fpcr # load user's rnd mode/prec + fmov.x PIBY2(%pc),%fp0 + bra t_pinx2 + +######################################################################### +# setox(): computes the exponential for a normalized input # +# setoxd(): computes the exponential for a denormalized input # +# setoxm1(): computes the exponential minus 1 for a normalized input # +# setoxm1d(): computes the exponential minus 1 for a denormalized input # +# # +# INPUT *************************************************************** # +# a0 = pointer to extended precision input # +# d0 = round precision,mode # +# # +# OUTPUT ************************************************************** # +# fp0 = exp(X) or exp(X)-1 # +# # +# ACCURACY and MONOTONICITY ******************************************* # +# The returned result is within 0.85 ulps in 64 significant bit, # +# i.e. within 0.5001 ulp to 53 bits if the result is subsequently # +# rounded to double precision. The result is provably monotonic # +# in double precision. # +# # +# ALGORITHM and IMPLEMENTATION **************************************** # +# # +# setoxd # +# ------ # +# Step 1. Set ans := 1.0 # +# # +# Step 2. Return ans := ans + sign(X)*2^(-126). Exit. # +# Notes: This will always generate one exception -- inexact. # +# # +# # +# setox # +# ----- # +# # +# Step 1. Filter out extreme cases of input argument. # +# 1.1 If |X| >= 2^(-65), go to Step 1.3. # +# 1.2 Go to Step 7. # +# 1.3 If |X| < 16380 log(2), go to Step 2. # +# 1.4 Go to Step 8. # +# Notes: The usual case should take the branches 1.1 -> 1.3 -> 2.# +# To avoid the use of floating-point comparisons, a # +# compact representation of |X| is used. This format is a # +# 32-bit integer, the upper (more significant) 16 bits # +# are the sign and biased exponent field of |X|; the # +# lower 16 bits are the 16 most significant fraction # +# (including the explicit bit) bits of |X|. Consequently, # +# the comparisons in Steps 1.1 and 1.3 can be performed # +# by integer comparison. Note also that the constant # +# 16380 log(2) used in Step 1.3 is also in the compact # +# form. Thus taking the branch to Step 2 guarantees # +# |X| < 16380 log(2). There is no harm to have a small # +# number of cases where |X| is less than, but close to, # +# 16380 log(2) and the branch to Step 9 is taken. # +# # +# Step 2. Calculate N = round-to-nearest-int( X * 64/log2 ). # +# 2.1 Set AdjFlag := 0 (indicates the branch 1.3 -> 2 # +# was taken) # +# 2.2 N := round-to-nearest-integer( X * 64/log2 ). # +# 2.3 Calculate J = N mod 64; so J = 0,1,2,..., # +# or 63. # +# 2.4 Calculate M = (N - J)/64; so N = 64M + J. # +# 2.5 Calculate the address of the stored value of # +# 2^(J/64). # +# 2.6 Create the value Scale = 2^M. # +# Notes: The calculation in 2.2 is really performed by # +# Z := X * constant # +# N := round-to-nearest-integer(Z) # +# where # +# constant := single-precision( 64/log 2 ). # +# # +# Using a single-precision constant avoids memory # +# access. Another effect of using a single-precision # +# "constant" is that the calculated value Z is # +# # +# Z = X*(64/log2)*(1+eps), |eps| <= 2^(-24). # +# # +# This error has to be considered later in Steps 3 and 4. # +# # +# Step 3. Calculate X - N*log2/64. # +# 3.1 R := X + N*L1, # +# where L1 := single-precision(-log2/64). # +# 3.2 R := R + N*L2, # +# L2 := extended-precision(-log2/64 - L1).# +# Notes: a) The way L1 and L2 are chosen ensures L1+L2 # +# approximate the value -log2/64 to 88 bits of accuracy. # +# b) N*L1 is exact because N is no longer than 22 bits # +# and L1 is no longer than 24 bits. # +# c) The calculation X+N*L1 is also exact due to # +# cancellation. Thus, R is practically X+N(L1+L2) to full # +# 64 bits. # +# d) It is important to estimate how large can |R| be # +# after Step 3.2. # +# # +# N = rnd-to-int( X*64/log2 (1+eps) ), |eps|<=2^(-24) # +# X*64/log2 (1+eps) = N + f, |f| <= 0.5 # +# X*64/log2 - N = f - eps*X 64/log2 # +# X - N*log2/64 = f*log2/64 - eps*X # +# # +# # +# Now |X| <= 16446 log2, thus # +# # +# |X - N*log2/64| <= (0.5 + 16446/2^(18))*log2/64 # +# <= 0.57 log2/64. # +# This bound will be used in Step 4. # +# # +# Step 4. Approximate exp(R)-1 by a polynomial # +# p = R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*A5)))) # +# Notes: a) In order to reduce memory access, the coefficients # +# are made as "short" as possible: A1 (which is 1/2), A4 # +# and A5 are single precision; A2 and A3 are double # +# precision. # +# b) Even with the restrictions above, # +# |p - (exp(R)-1)| < 2^(-68.8) for all |R| <= 0.0062. # +# Note that 0.0062 is slightly bigger than 0.57 log2/64. # +# c) To fully utilize the pipeline, p is separated into # +# two independent pieces of roughly equal complexities # +# p = [ R + R*S*(A2 + S*A4) ] + # +# [ S*(A1 + S*(A3 + S*A5)) ] # +# where S = R*R. # +# # +# Step 5. Compute 2^(J/64)*exp(R) = 2^(J/64)*(1+p) by # +# ans := T + ( T*p + t) # +# where T and t are the stored values for 2^(J/64). # +# Notes: 2^(J/64) is stored as T and t where T+t approximates # +# 2^(J/64) to roughly 85 bits; T is in extended precision # +# and t is in single precision. Note also that T is # +# rounded to 62 bits so that the last two bits of T are # +# zero. The reason for such a special form is that T-1, # +# T-2, and T-8 will all be exact --- a property that will # +# give much more accurate computation of the function # +# EXPM1. # +# # +# Step 6. Reconstruction of exp(X) # +# exp(X) = 2^M * 2^(J/64) * exp(R). # +# 6.1 If AdjFlag = 0, go to 6.3 # +# 6.2 ans := ans * AdjScale # +# 6.3 Restore the user FPCR # +# 6.4 Return ans := ans * Scale. Exit. # +# Notes: If AdjFlag = 0, we have X = Mlog2 + Jlog2/64 + R, # +# |M| <= 16380, and Scale = 2^M. Moreover, exp(X) will # +# neither overflow nor underflow. If AdjFlag = 1, that # +# means that # +# X = (M1+M)log2 + Jlog2/64 + R, |M1+M| >= 16380. # +# Hence, exp(X) may overflow or underflow or neither. # +# When that is the case, AdjScale = 2^(M1) where M1 is # +# approximately M. Thus 6.2 will never cause # +# over/underflow. Possible exception in 6.4 is overflow # +# or underflow. The inexact exception is not generated in # +# 6.4. Although one can argue that the inexact flag # +# should always be raised, to simulate that exception # +# cost to much than the flag is worth in practical uses. # +# # +# Step 7. Return 1 + X. # +# 7.1 ans := X # +# 7.2 Restore user FPCR. # +# 7.3 Return ans := 1 + ans. Exit # +# Notes: For non-zero X, the inexact exception will always be # +# raised by 7.3. That is the only exception raised by 7.3.# +# Note also that we use the FMOVEM instruction to move X # +# in Step 7.1 to avoid unnecessary trapping. (Although # +# the FMOVEM may not seem relevant since X is normalized, # +# the precaution will be useful in the library version of # +# this code where the separate entry for denormalized # +# inputs will be done away with.) # +# # +# Step 8. Handle exp(X) where |X| >= 16380log2. # +# 8.1 If |X| > 16480 log2, go to Step 9. # +# (mimic 2.2 - 2.6) # +# 8.2 N := round-to-integer( X * 64/log2 ) # +# 8.3 Calculate J = N mod 64, J = 0,1,...,63 # +# 8.4 K := (N-J)/64, M1 := truncate(K/2), M = K-M1, # +# AdjFlag := 1. # +# 8.5 Calculate the address of the stored value # +# 2^(J/64). # +# 8.6 Create the values Scale = 2^M, AdjScale = 2^M1. # +# 8.7 Go to Step 3. # +# Notes: Refer to notes for 2.2 - 2.6. # +# # +# Step 9. Handle exp(X), |X| > 16480 log2. # +# 9.1 If X < 0, go to 9.3 # +# 9.2 ans := Huge, go to 9.4 # +# 9.3 ans := Tiny. # +# 9.4 Restore user FPCR. # +# 9.5 Return ans := ans * ans. Exit. # +# Notes: Exp(X) will surely overflow or underflow, depending on # +# X's sign. "Huge" and "Tiny" are respectively large/tiny # +# extended-precision numbers whose square over/underflow # +# with an inexact result. Thus, 9.5 always raises the # +# inexact together with either overflow or underflow. # +# # +# setoxm1d # +# -------- # +# # +# Step 1. Set ans := 0 # +# # +# Step 2. Return ans := X + ans. Exit. # +# Notes: This will return X with the appropriate rounding # +# precision prescribed by the user FPCR. # +# # +# setoxm1 # +# ------- # +# # +# Step 1. Check |X| # +# 1.1 If |X| >= 1/4, go to Step 1.3. # +# 1.2 Go to Step 7. # +# 1.3 If |X| < 70 log(2), go to Step 2. # +# 1.4 Go to Step 10. # +# Notes: The usual case should take the branches 1.1 -> 1.3 -> 2.# +# However, it is conceivable |X| can be small very often # +# because EXPM1 is intended to evaluate exp(X)-1 # +# accurately when |X| is small. For further details on # +# the comparisons, see the notes on Step 1 of setox. # +# # +# Step 2. Calculate N = round-to-nearest-int( X * 64/log2 ). # +# 2.1 N := round-to-nearest-integer( X * 64/log2 ). # +# 2.2 Calculate J = N mod 64; so J = 0,1,2,..., # +# or 63. # +# 2.3 Calculate M = (N - J)/64; so N = 64M + J. # +# 2.4 Calculate the address of the stored value of # +# 2^(J/64). # +# 2.5 Create the values Sc = 2^M and # +# OnebySc := -2^(-M). # +# Notes: See the notes on Step 2 of setox. # +# # +# Step 3. Calculate X - N*log2/64. # +# 3.1 R := X + N*L1, # +# where L1 := single-precision(-log2/64). # +# 3.2 R := R + N*L2, # +# L2 := extended-precision(-log2/64 - L1).# +# Notes: Applying the analysis of Step 3 of setox in this case # +# shows that |R| <= 0.0055 (note that |X| <= 70 log2 in # +# this case). # +# # +# Step 4. Approximate exp(R)-1 by a polynomial # +# p = R+R*R*(A1+R*(A2+R*(A3+R*(A4+R*(A5+R*A6))))) # +# Notes: a) In order to reduce memory access, the coefficients # +# are made as "short" as possible: A1 (which is 1/2), A5 # +# and A6 are single precision; A2, A3 and A4 are double # +# precision. # +# b) Even with the restriction above, # +# |p - (exp(R)-1)| < |R| * 2^(-72.7) # +# for all |R| <= 0.0055. # +# c) To fully utilize the pipeline, p is separated into # +# two independent pieces of roughly equal complexity # +# p = [ R*S*(A2 + S*(A4 + S*A6)) ] + # +# [ R + S*(A1 + S*(A3 + S*A5)) ] # +# where S = R*R. # +# # +# Step 5. Compute 2^(J/64)*p by # +# p := T*p # +# where T and t are the stored values for 2^(J/64). # +# Notes: 2^(J/64) is stored as T and t where T+t approximates # +# 2^(J/64) to roughly 85 bits; T is in extended precision # +# and t is in single precision. Note also that T is # +# rounded to 62 bits so that the last two bits of T are # +# zero. The reason for such a special form is that T-1, # +# T-2, and T-8 will all be exact --- a property that will # +# be exploited in Step 6 below. The total relative error # +# in p is no bigger than 2^(-67.7) compared to the final # +# result. # +# # +# Step 6. Reconstruction of exp(X)-1 # +# exp(X)-1 = 2^M * ( 2^(J/64) + p - 2^(-M) ). # +# 6.1 If M <= 63, go to Step 6.3. # +# 6.2 ans := T + (p + (t + OnebySc)). Go to 6.6 # +# 6.3 If M >= -3, go to 6.5. # +# 6.4 ans := (T + (p + t)) + OnebySc. Go to 6.6 # +# 6.5 ans := (T + OnebySc) + (p + t). # +# 6.6 Restore user FPCR. # +# 6.7 Return ans := Sc * ans. Exit. # +# Notes: The various arrangements of the expressions give # +# accurate evaluations. # +# # +# Step 7. exp(X)-1 for |X| < 1/4. # +# 7.1 If |X| >= 2^(-65), go to Step 9. # +# 7.2 Go to Step 8. # +# # +# Step 8. Calculate exp(X)-1, |X| < 2^(-65). # +# 8.1 If |X| < 2^(-16312), goto 8.3 # +# 8.2 Restore FPCR; return ans := X - 2^(-16382). # +# Exit. # +# 8.3 X := X * 2^(140). # +# 8.4 Restore FPCR; ans := ans - 2^(-16382). # +# Return ans := ans*2^(140). Exit # +# Notes: The idea is to return "X - tiny" under the user # +# precision and rounding modes. To avoid unnecessary # +# inefficiency, we stay away from denormalized numbers # +# the best we can. For |X| >= 2^(-16312), the # +# straightforward 8.2 generates the inexact exception as # +# the case warrants. # +# # +# Step 9. Calculate exp(X)-1, |X| < 1/4, by a polynomial # +# p = X + X*X*(B1 + X*(B2 + ... + X*B12)) # +# Notes: a) In order to reduce memory access, the coefficients # +# are made as "short" as possible: B1 (which is 1/2), B9 # +# to B12 are single precision; B3 to B8 are double # +# precision; and B2 is double extended. # +# b) Even with the restriction above, # +# |p - (exp(X)-1)| < |X| 2^(-70.6) # +# for all |X| <= 0.251. # +# Note that 0.251 is slightly bigger than 1/4. # +# c) To fully preserve accuracy, the polynomial is # +# computed as # +# X + ( S*B1 + Q ) where S = X*X and # +# Q = X*S*(B2 + X*(B3 + ... + X*B12)) # +# d) To fully utilize the pipeline, Q is separated into # +# two independent pieces of roughly equal complexity # +# Q = [ X*S*(B2 + S*(B4 + ... + S*B12)) ] + # +# [ S*S*(B3 + S*(B5 + ... + S*B11)) ] # +# # +# Step 10. Calculate exp(X)-1 for |X| >= 70 log 2. # +# 10.1 If X >= 70log2 , exp(X) - 1 = exp(X) for all # +# practical purposes. Therefore, go to Step 1 of setox. # +# 10.2 If X <= -70log2, exp(X) - 1 = -1 for all practical # +# purposes. # +# ans := -1 # +# Restore user FPCR # +# Return ans := ans + 2^(-126). Exit. # +# Notes: 10.2 will always create an inexact and return -1 + tiny # +# in the user rounding precision and mode. # +# # +######################################################################### + +L2: long 0x3FDC0000,0x82E30865,0x4361C4C6,0x00000000 + +EEXPA3: long 0x3FA55555,0x55554CC1 +EEXPA2: long 0x3FC55555,0x55554A54 + +EM1A4: long 0x3F811111,0x11174385 +EM1A3: long 0x3FA55555,0x55554F5A + +EM1A2: long 0x3FC55555,0x55555555,0x00000000,0x00000000 + +EM1B8: long 0x3EC71DE3,0xA5774682 +EM1B7: long 0x3EFA01A0,0x19D7CB68 + +EM1B6: long 0x3F2A01A0,0x1A019DF3 +EM1B5: long 0x3F56C16C,0x16C170E2 + +EM1B4: long 0x3F811111,0x11111111 +EM1B3: long 0x3FA55555,0x55555555 + +EM1B2: long 0x3FFC0000,0xAAAAAAAA,0xAAAAAAAB + long 0x00000000 + +TWO140: long 0x48B00000,0x00000000 +TWON140: + long 0x37300000,0x00000000 + +EEXPTBL: + long 0x3FFF0000,0x80000000,0x00000000,0x00000000 + long 0x3FFF0000,0x8164D1F3,0xBC030774,0x9F841A9B + long 0x3FFF0000,0x82CD8698,0xAC2BA1D8,0x9FC1D5B9 + long 0x3FFF0000,0x843A28C3,0xACDE4048,0xA0728369 + long 0x3FFF0000,0x85AAC367,0xCC487B14,0x1FC5C95C + long 0x3FFF0000,0x871F6196,0x9E8D1010,0x1EE85C9F + long 0x3FFF0000,0x88980E80,0x92DA8528,0x9FA20729 + long 0x3FFF0000,0x8A14D575,0x496EFD9C,0xA07BF9AF + long 0x3FFF0000,0x8B95C1E3,0xEA8BD6E8,0xA0020DCF + long 0x3FFF0000,0x8D1ADF5B,0x7E5BA9E4,0x205A63DA + long 0x3FFF0000,0x8EA4398B,0x45CD53C0,0x1EB70051 + long 0x3FFF0000,0x9031DC43,0x1466B1DC,0x1F6EB029 + long 0x3FFF0000,0x91C3D373,0xAB11C338,0xA0781494 + long 0x3FFF0000,0x935A2B2F,0x13E6E92C,0x9EB319B0 + long 0x3FFF0000,0x94F4EFA8,0xFEF70960,0x2017457D + long 0x3FFF0000,0x96942D37,0x20185A00,0x1F11D537 + long 0x3FFF0000,0x9837F051,0x8DB8A970,0x9FB952DD + long 0x3FFF0000,0x99E04593,0x20B7FA64,0x1FE43087 + long 0x3FFF0000,0x9B8D39B9,0xD54E5538,0x1FA2A818 + long 0x3FFF0000,0x9D3ED9A7,0x2CFFB750,0x1FDE494D + long 0x3FFF0000,0x9EF53260,0x91A111AC,0x20504890 + long 0x3FFF0000,0xA0B0510F,0xB9714FC4,0xA073691C + long 0x3FFF0000,0xA2704303,0x0C496818,0x1F9B7A05 + long 0x3FFF0000,0xA43515AE,0x09E680A0,0xA0797126 + long 0x3FFF0000,0xA5FED6A9,0xB15138EC,0xA071A140 + long 0x3FFF0000,0xA7CD93B4,0xE9653568,0x204F62DA + long 0x3FFF0000,0xA9A15AB4,0xEA7C0EF8,0x1F283C4A + long 0x3FFF0000,0xAB7A39B5,0xA93ED338,0x9F9A7FDC + long 0x3FFF0000,0xAD583EEA,0x42A14AC8,0xA05B3FAC + long 0x3FFF0000,0xAF3B78AD,0x690A4374,0x1FDF2610 + long 0x3FFF0000,0xB123F581,0xD2AC2590,0x9F705F90 + long 0x3FFF0000,0xB311C412,0xA9112488,0x201F678A + long 0x3FFF0000,0xB504F333,0xF9DE6484,0x1F32FB13 + long 0x3FFF0000,0xB6FD91E3,0x28D17790,0x20038B30 + long 0x3FFF0000,0xB8FBAF47,0x62FB9EE8,0x200DC3CC + long 0x3FFF0000,0xBAFF5AB2,0x133E45FC,0x9F8B2AE6 + long 0x3FFF0000,0xBD08A39F,0x580C36C0,0xA02BBF70 + long 0x3FFF0000,0xBF1799B6,0x7A731084,0xA00BF518 + long 0x3FFF0000,0xC12C4CCA,0x66709458,0xA041DD41 + long 0x3FFF0000,0xC346CCDA,0x24976408,0x9FDF137B + long 0x3FFF0000,0xC5672A11,0x5506DADC,0x201F1568 + long 0x3FFF0000,0xC78D74C8,0xABB9B15C,0x1FC13A2E + long 0x3FFF0000,0xC9B9BD86,0x6E2F27A4,0xA03F8F03 + long 0x3FFF0000,0xCBEC14FE,0xF2727C5C,0x1FF4907D + long 0x3FFF0000,0xCE248C15,0x1F8480E4,0x9E6E53E4 + long 0x3FFF0000,0xD06333DA,0xEF2B2594,0x1FD6D45C + long 0x3FFF0000,0xD2A81D91,0xF12AE45C,0xA076EDB9 + long 0x3FFF0000,0xD4F35AAB,0xCFEDFA20,0x9FA6DE21 + long 0x3FFF0000,0xD744FCCA,0xD69D6AF4,0x1EE69A2F + long 0x3FFF0000,0xD99D15C2,0x78AFD7B4,0x207F439F + long 0x3FFF0000,0xDBFBB797,0xDAF23754,0x201EC207 + long 0x3FFF0000,0xDE60F482,0x5E0E9124,0x9E8BE175 + long 0x3FFF0000,0xE0CCDEEC,0x2A94E110,0x20032C4B + long 0x3FFF0000,0xE33F8972,0xBE8A5A50,0x2004DFF5 + long 0x3FFF0000,0xE5B906E7,0x7C8348A8,0x1E72F47A + long 0x3FFF0000,0xE8396A50,0x3C4BDC68,0x1F722F22 + long 0x3FFF0000,0xEAC0C6E7,0xDD243930,0xA017E945 + long 0x3FFF0000,0xED4F301E,0xD9942B84,0x1F401A5B + long 0x3FFF0000,0xEFE4B99B,0xDCDAF5CC,0x9FB9A9E3 + long 0x3FFF0000,0xF281773C,0x59FFB138,0x20744C05 + long 0x3FFF0000,0xF5257D15,0x2486CC2C,0x1F773A19 + long 0x3FFF0000,0xF7D0DF73,0x0AD13BB8,0x1FFE90D5 + long 0x3FFF0000,0xFA83B2DB,0x722A033C,0xA041ED22 + long 0x3FFF0000,0xFD3E0C0C,0xF486C174,0x1F853F3A + + set ADJFLAG,L_SCR2 + set SCALE,FP_SCR0 + set ADJSCALE,FP_SCR1 + set SC,FP_SCR0 + set ONEBYSC,FP_SCR1 + + global setox +setox: +#--entry point for EXP(X), here X is finite, non-zero, and not NaN's + +#--Step 1. + mov.l (%a0),%d1 # load part of input X + and.l &0x7FFF0000,%d1 # biased expo. of X + cmp.l %d1,&0x3FBE0000 # 2^(-65) + bge.b EXPC1 # normal case + bra EXPSM + +EXPC1: +#--The case |X| >= 2^(-65) + mov.w 4(%a0),%d1 # expo. and partial sig. of |X| + cmp.l %d1,&0x400CB167 # 16380 log2 trunc. 16 bits + blt.b EXPMAIN # normal case + bra EEXPBIG + +EXPMAIN: +#--Step 2. +#--This is the normal branch: 2^(-65) <= |X| < 16380 log2. + fmov.x (%a0),%fp0 # load input from (a0) + + fmov.x %fp0,%fp1 + fmul.s &0x42B8AA3B,%fp0 # 64/log2 * X + fmovm.x &0xc,-(%sp) # save fp2 {%fp2/%fp3} + mov.l &0,ADJFLAG(%a6) + fmov.l %fp0,%d1 # N = int( X * 64/log2 ) + lea EEXPTBL(%pc),%a1 + fmov.l %d1,%fp0 # convert to floating-format + + mov.l %d1,L_SCR1(%a6) # save N temporarily + and.l &0x3F,%d1 # D0 is J = N mod 64 + lsl.l &4,%d1 + add.l %d1,%a1 # address of 2^(J/64) + mov.l L_SCR1(%a6),%d1 + asr.l &6,%d1 # D0 is M + add.w &0x3FFF,%d1 # biased expo. of 2^(M) + mov.w L2(%pc),L_SCR1(%a6) # prefetch L2, no need in CB + +EXPCONT1: +#--Step 3. +#--fp1,fp2 saved on the stack. fp0 is N, fp1 is X, +#--a0 points to 2^(J/64), D0 is biased expo. of 2^(M) + fmov.x %fp0,%fp2 + fmul.s &0xBC317218,%fp0 # N * L1, L1 = lead(-log2/64) + fmul.x L2(%pc),%fp2 # N * L2, L1+L2 = -log2/64 + fadd.x %fp1,%fp0 # X + N*L1 + fadd.x %fp2,%fp0 # fp0 is R, reduced arg. + +#--Step 4. +#--WE NOW COMPUTE EXP(R)-1 BY A POLYNOMIAL +#-- R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*A5)))) +#--TO FULLY UTILIZE THE PIPELINE, WE COMPUTE S = R*R +#--[R+R*S*(A2+S*A4)] + [S*(A1+S*(A3+S*A5))] + + fmov.x %fp0,%fp1 + fmul.x %fp1,%fp1 # fp1 IS S = R*R + + fmov.s &0x3AB60B70,%fp2 # fp2 IS A5 + + fmul.x %fp1,%fp2 # fp2 IS S*A5 + fmov.x %fp1,%fp3 + fmul.s &0x3C088895,%fp3 # fp3 IS S*A4 + + fadd.d EEXPA3(%pc),%fp2 # fp2 IS A3+S*A5 + fadd.d EEXPA2(%pc),%fp3 # fp3 IS A2+S*A4 + + fmul.x %fp1,%fp2 # fp2 IS S*(A3+S*A5) + mov.w %d1,SCALE(%a6) # SCALE is 2^(M) in extended + mov.l &0x80000000,SCALE+4(%a6) + clr.l SCALE+8(%a6) + + fmul.x %fp1,%fp3 # fp3 IS S*(A2+S*A4) + + fadd.s &0x3F000000,%fp2 # fp2 IS A1+S*(A3+S*A5) + fmul.x %fp0,%fp3 # fp3 IS R*S*(A2+S*A4) + + fmul.x %fp1,%fp2 # fp2 IS S*(A1+S*(A3+S*A5)) + fadd.x %fp3,%fp0 # fp0 IS R+R*S*(A2+S*A4), + + fmov.x (%a1)+,%fp1 # fp1 is lead. pt. of 2^(J/64) + fadd.x %fp2,%fp0 # fp0 is EXP(R) - 1 + +#--Step 5 +#--final reconstruction process +#--EXP(X) = 2^M * ( 2^(J/64) + 2^(J/64)*(EXP(R)-1) ) + + fmul.x %fp1,%fp0 # 2^(J/64)*(Exp(R)-1) + fmovm.x (%sp)+,&0x30 # fp2 restored {%fp2/%fp3} + fadd.s (%a1),%fp0 # accurate 2^(J/64) + + fadd.x %fp1,%fp0 # 2^(J/64) + 2^(J/64)*... + mov.l ADJFLAG(%a6),%d1 + +#--Step 6 + tst.l %d1 + beq.b NORMAL +ADJUST: + fmul.x ADJSCALE(%a6),%fp0 +NORMAL: + fmov.l %d0,%fpcr # restore user FPCR + mov.b &FMUL_OP,%d1 # last inst is MUL + fmul.x SCALE(%a6),%fp0 # multiply 2^(M) + bra t_catch + +EXPSM: +#--Step 7 + fmovm.x (%a0),&0x80 # load X + fmov.l %d0,%fpcr + fadd.s &0x3F800000,%fp0 # 1+X in user mode + bra t_pinx2 + +EEXPBIG: +#--Step 8 + cmp.l %d1,&0x400CB27C # 16480 log2 + bgt.b EXP2BIG +#--Steps 8.2 -- 8.6 + fmov.x (%a0),%fp0 # load input from (a0) + + fmov.x %fp0,%fp1 + fmul.s &0x42B8AA3B,%fp0 # 64/log2 * X + fmovm.x &0xc,-(%sp) # save fp2 {%fp2/%fp3} + mov.l &1,ADJFLAG(%a6) + fmov.l %fp0,%d1 # N = int( X * 64/log2 ) + lea EEXPTBL(%pc),%a1 + fmov.l %d1,%fp0 # convert to floating-format + mov.l %d1,L_SCR1(%a6) # save N temporarily + and.l &0x3F,%d1 # D0 is J = N mod 64 + lsl.l &4,%d1 + add.l %d1,%a1 # address of 2^(J/64) + mov.l L_SCR1(%a6),%d1 + asr.l &6,%d1 # D0 is K + mov.l %d1,L_SCR1(%a6) # save K temporarily + asr.l &1,%d1 # D0 is M1 + sub.l %d1,L_SCR1(%a6) # a1 is M + add.w &0x3FFF,%d1 # biased expo. of 2^(M1) + mov.w %d1,ADJSCALE(%a6) # ADJSCALE := 2^(M1) + mov.l &0x80000000,ADJSCALE+4(%a6) + clr.l ADJSCALE+8(%a6) + mov.l L_SCR1(%a6),%d1 # D0 is M + add.w &0x3FFF,%d1 # biased expo. of 2^(M) + bra.w EXPCONT1 # go back to Step 3 + +EXP2BIG: +#--Step 9 + tst.b (%a0) # is X positive or negative? + bmi t_unfl2 + bra t_ovfl2 + + global setoxd +setoxd: +#--entry point for EXP(X), X is denormalized + mov.l (%a0),-(%sp) + andi.l &0x80000000,(%sp) + ori.l &0x00800000,(%sp) # sign(X)*2^(-126) + + fmov.s &0x3F800000,%fp0 + + fmov.l %d0,%fpcr + fadd.s (%sp)+,%fp0 + bra t_pinx2 + + global setoxm1 +setoxm1: +#--entry point for EXPM1(X), here X is finite, non-zero, non-NaN + +#--Step 1. +#--Step 1.1 + mov.l (%a0),%d1 # load part of input X + and.l &0x7FFF0000,%d1 # biased expo. of X + cmp.l %d1,&0x3FFD0000 # 1/4 + bge.b EM1CON1 # |X| >= 1/4 + bra EM1SM + +EM1CON1: +#--Step 1.3 +#--The case |X| >= 1/4 + mov.w 4(%a0),%d1 # expo. and partial sig. of |X| + cmp.l %d1,&0x4004C215 # 70log2 rounded up to 16 bits + ble.b EM1MAIN # 1/4 <= |X| <= 70log2 + bra EM1BIG + +EM1MAIN: +#--Step 2. +#--This is the case: 1/4 <= |X| <= 70 log2. + fmov.x (%a0),%fp0 # load input from (a0) + + fmov.x %fp0,%fp1 + fmul.s &0x42B8AA3B,%fp0 # 64/log2 * X + fmovm.x &0xc,-(%sp) # save fp2 {%fp2/%fp3} + fmov.l %fp0,%d1 # N = int( X * 64/log2 ) + lea EEXPTBL(%pc),%a1 + fmov.l %d1,%fp0 # convert to floating-format + + mov.l %d1,L_SCR1(%a6) # save N temporarily + and.l &0x3F,%d1 # D0 is J = N mod 64 + lsl.l &4,%d1 + add.l %d1,%a1 # address of 2^(J/64) + mov.l L_SCR1(%a6),%d1 + asr.l &6,%d1 # D0 is M + mov.l %d1,L_SCR1(%a6) # save a copy of M + +#--Step 3. +#--fp1,fp2 saved on the stack. fp0 is N, fp1 is X, +#--a0 points to 2^(J/64), D0 and a1 both contain M + fmov.x %fp0,%fp2 + fmul.s &0xBC317218,%fp0 # N * L1, L1 = lead(-log2/64) + fmul.x L2(%pc),%fp2 # N * L2, L1+L2 = -log2/64 + fadd.x %fp1,%fp0 # X + N*L1 + fadd.x %fp2,%fp0 # fp0 is R, reduced arg. + add.w &0x3FFF,%d1 # D0 is biased expo. of 2^M + +#--Step 4. +#--WE NOW COMPUTE EXP(R)-1 BY A POLYNOMIAL +#-- R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*(A5 + R*A6))))) +#--TO FULLY UTILIZE THE PIPELINE, WE COMPUTE S = R*R +#--[R*S*(A2+S*(A4+S*A6))] + [R+S*(A1+S*(A3+S*A5))] + + fmov.x %fp0,%fp1 + fmul.x %fp1,%fp1 # fp1 IS S = R*R + + fmov.s &0x3950097B,%fp2 # fp2 IS a6 + + fmul.x %fp1,%fp2 # fp2 IS S*A6 + fmov.x %fp1,%fp3 + fmul.s &0x3AB60B6A,%fp3 # fp3 IS S*A5 + + fadd.d EM1A4(%pc),%fp2 # fp2 IS A4+S*A6 + fadd.d EM1A3(%pc),%fp3 # fp3 IS A3+S*A5 + mov.w %d1,SC(%a6) # SC is 2^(M) in extended + mov.l &0x80000000,SC+4(%a6) + clr.l SC+8(%a6) + + fmul.x %fp1,%fp2 # fp2 IS S*(A4+S*A6) + mov.l L_SCR1(%a6),%d1 # D0 is M + neg.w %d1 # D0 is -M + fmul.x %fp1,%fp3 # fp3 IS S*(A3+S*A5) + add.w &0x3FFF,%d1 # biased expo. of 2^(-M) + fadd.d EM1A2(%pc),%fp2 # fp2 IS A2+S*(A4+S*A6) + fadd.s &0x3F000000,%fp3 # fp3 IS A1+S*(A3+S*A5) + + fmul.x %fp1,%fp2 # fp2 IS S*(A2+S*(A4+S*A6)) + or.w &0x8000,%d1 # signed/expo. of -2^(-M) + mov.w %d1,ONEBYSC(%a6) # OnebySc is -2^(-M) + mov.l &0x80000000,ONEBYSC+4(%a6) + clr.l ONEBYSC+8(%a6) + fmul.x %fp3,%fp1 # fp1 IS S*(A1+S*(A3+S*A5)) + + fmul.x %fp0,%fp2 # fp2 IS R*S*(A2+S*(A4+S*A6)) + fadd.x %fp1,%fp0 # fp0 IS R+S*(A1+S*(A3+S*A5)) + + fadd.x %fp2,%fp0 # fp0 IS EXP(R)-1 + + fmovm.x (%sp)+,&0x30 # fp2 restored {%fp2/%fp3} + +#--Step 5 +#--Compute 2^(J/64)*p + + fmul.x (%a1),%fp0 # 2^(J/64)*(Exp(R)-1) + +#--Step 6 +#--Step 6.1 + mov.l L_SCR1(%a6),%d1 # retrieve M + cmp.l %d1,&63 + ble.b MLE63 +#--Step 6.2 M >= 64 + fmov.s 12(%a1),%fp1 # fp1 is t + fadd.x ONEBYSC(%a6),%fp1 # fp1 is t+OnebySc + fadd.x %fp1,%fp0 # p+(t+OnebySc), fp1 released + fadd.x (%a1),%fp0 # T+(p+(t+OnebySc)) + bra EM1SCALE +MLE63: +#--Step 6.3 M <= 63 + cmp.l %d1,&-3 + bge.b MGEN3 +MLTN3: +#--Step 6.4 M <= -4 + fadd.s 12(%a1),%fp0 # p+t + fadd.x (%a1),%fp0 # T+(p+t) + fadd.x ONEBYSC(%a6),%fp0 # OnebySc + (T+(p+t)) + bra EM1SCALE +MGEN3: +#--Step 6.5 -3 <= M <= 63 + fmov.x (%a1)+,%fp1 # fp1 is T + fadd.s (%a1),%fp0 # fp0 is p+t + fadd.x ONEBYSC(%a6),%fp1 # fp1 is T+OnebySc + fadd.x %fp1,%fp0 # (T+OnebySc)+(p+t) + +EM1SCALE: +#--Step 6.6 + fmov.l %d0,%fpcr + fmul.x SC(%a6),%fp0 + bra t_inx2 + +EM1SM: +#--Step 7 |X| < 1/4. + cmp.l %d1,&0x3FBE0000 # 2^(-65) + bge.b EM1POLY + +EM1TINY: +#--Step 8 |X| < 2^(-65) + cmp.l %d1,&0x00330000 # 2^(-16312) + blt.b EM12TINY +#--Step 8.2 + mov.l &0x80010000,SC(%a6) # SC is -2^(-16382) + mov.l &0x80000000,SC+4(%a6) + clr.l SC+8(%a6) + fmov.x (%a0),%fp0 + fmov.l %d0,%fpcr + mov.b &FADD_OP,%d1 # last inst is ADD + fadd.x SC(%a6),%fp0 + bra t_catch + +EM12TINY: +#--Step 8.3 + fmov.x (%a0),%fp0 + fmul.d TWO140(%pc),%fp0 + mov.l &0x80010000,SC(%a6) + mov.l &0x80000000,SC+4(%a6) + clr.l SC+8(%a6) + fadd.x SC(%a6),%fp0 + fmov.l %d0,%fpcr + mov.b &FMUL_OP,%d1 # last inst is MUL + fmul.d TWON140(%pc),%fp0 + bra t_catch + +EM1POLY: +#--Step 9 exp(X)-1 by a simple polynomial + fmov.x (%a0),%fp0 # fp0 is X + fmul.x %fp0,%fp0 # fp0 is S := X*X + fmovm.x &0xc,-(%sp) # save fp2 {%fp2/%fp3} + fmov.s &0x2F30CAA8,%fp1 # fp1 is B12 + fmul.x %fp0,%fp1 # fp1 is S*B12 + fmov.s &0x310F8290,%fp2 # fp2 is B11 + fadd.s &0x32D73220,%fp1 # fp1 is B10+S*B12 + + fmul.x %fp0,%fp2 # fp2 is S*B11 + fmul.x %fp0,%fp1 # fp1 is S*(B10 + ... + + fadd.s &0x3493F281,%fp2 # fp2 is B9+S*... + fadd.d EM1B8(%pc),%fp1 # fp1 is B8+S*... + + fmul.x %fp0,%fp2 # fp2 is S*(B9+... + fmul.x %fp0,%fp1 # fp1 is S*(B8+... + + fadd.d EM1B7(%pc),%fp2 # fp2 is B7+S*... + fadd.d EM1B6(%pc),%fp1 # fp1 is B6+S*... + + fmul.x %fp0,%fp2 # fp2 is S*(B7+... + fmul.x %fp0,%fp1 # fp1 is S*(B6+... + + fadd.d EM1B5(%pc),%fp2 # fp2 is B5+S*... + fadd.d EM1B4(%pc),%fp1 # fp1 is B4+S*... + + fmul.x %fp0,%fp2 # fp2 is S*(B5+... + fmul.x %fp0,%fp1 # fp1 is S*(B4+... + + fadd.d EM1B3(%pc),%fp2 # fp2 is B3+S*... + fadd.x EM1B2(%pc),%fp1 # fp1 is B2+S*... + + fmul.x %fp0,%fp2 # fp2 is S*(B3+... + fmul.x %fp0,%fp1 # fp1 is S*(B2+... + + fmul.x %fp0,%fp2 # fp2 is S*S*(B3+...) + fmul.x (%a0),%fp1 # fp1 is X*S*(B2... + + fmul.s &0x3F000000,%fp0 # fp0 is S*B1 + fadd.x %fp2,%fp1 # fp1 is Q + + fmovm.x (%sp)+,&0x30 # fp2 restored {%fp2/%fp3} + + fadd.x %fp1,%fp0 # fp0 is S*B1+Q + + fmov.l %d0,%fpcr + fadd.x (%a0),%fp0 + bra t_inx2 + +EM1BIG: +#--Step 10 |X| > 70 log2 + mov.l (%a0),%d1 + cmp.l %d1,&0 + bgt.w EXPC1 +#--Step 10.2 + fmov.s &0xBF800000,%fp0 # fp0 is -1 + fmov.l %d0,%fpcr + fadd.s &0x00800000,%fp0 # -1 + 2^(-126) + bra t_minx2 + + global setoxm1d +setoxm1d: +#--entry point for EXPM1(X), here X is denormalized +#--Step 0. + bra t_extdnrm + +######################################################################### +# sgetexp(): returns the exponent portion of the input argument. # +# The exponent bias is removed and the exponent value is # +# returned as an extended precision number in fp0. # +# sgetexpd(): handles denormalized numbers. # +# # +# sgetman(): extracts the mantissa of the input argument. The # +# mantissa is converted to an extended precision number w/ # +# an exponent of $3fff and is returned in fp0. The range of # +# the result is [1.0 - 2.0). # +# sgetmand(): handles denormalized numbers. # +# # +# INPUT *************************************************************** # +# a0 = pointer to extended precision input # +# # +# OUTPUT ************************************************************** # +# fp0 = exponent(X) or mantissa(X) # +# # +######################################################################### + + global sgetexp +sgetexp: + mov.w SRC_EX(%a0),%d0 # get the exponent + bclr &0xf,%d0 # clear the sign bit + subi.w &0x3fff,%d0 # subtract off the bias + fmov.w %d0,%fp0 # return exp in fp0 + blt.b sgetexpn # it's negative + rts + +sgetexpn: + mov.b &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit + rts + + global sgetexpd +sgetexpd: + bsr.l norm # normalize + neg.w %d0 # new exp = -(shft amt) + subi.w &0x3fff,%d0 # subtract off the bias + fmov.w %d0,%fp0 # return exp in fp0 + mov.b &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit + rts + + global sgetman +sgetman: + mov.w SRC_EX(%a0),%d0 # get the exp + ori.w &0x7fff,%d0 # clear old exp + bclr &0xe,%d0 # make it the new exp +-3fff + +# here, we build the result in a tmp location so as not to disturb the input + mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) # copy to tmp loc + mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) # copy to tmp loc + mov.w %d0,FP_SCR0_EX(%a6) # insert new exponent + fmov.x FP_SCR0(%a6),%fp0 # put new value back in fp0 + bmi.b sgetmann # it's negative + rts + +sgetmann: + mov.b &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit + rts + +# +# For denormalized numbers, shift the mantissa until the j-bit = 1, +# then load the exponent with +/1 $3fff. +# + global sgetmand +sgetmand: + bsr.l norm # normalize exponent + bra.b sgetman + +######################################################################### +# scosh(): computes the hyperbolic cosine of a normalized input # +# scoshd(): computes the hyperbolic cosine of a denormalized input # +# # +# INPUT *************************************************************** # +# a0 = pointer to extended precision input # +# d0 = round precision,mode # +# # +# OUTPUT ************************************************************** # +# fp0 = cosh(X) # +# # +# ACCURACY and MONOTONICITY ******************************************* # +# The returned result is within 3 ulps in 64 significant bit, # +# i.e. within 0.5001 ulp to 53 bits if the result is subsequently # +# rounded to double precision. The result is provably monotonic # +# in double precision. # +# # +# ALGORITHM *********************************************************** # +# # +# COSH # +# 1. If |X| > 16380 log2, go to 3. # +# # +# 2. (|X| <= 16380 log2) Cosh(X) is obtained by the formulae # +# y = |X|, z = exp(Y), and # +# cosh(X) = (1/2)*( z + 1/z ). # +# Exit. # +# # +# 3. (|X| > 16380 log2). If |X| > 16480 log2, go to 5. # +# # +# 4. (16380 log2 < |X| <= 16480 log2) # +# cosh(X) = sign(X) * exp(|X|)/2. # +# However, invoking exp(|X|) may cause premature # +# overflow. Thus, we calculate sinh(X) as follows: # +# Y := |X| # +# Fact := 2**(16380) # +# Y' := Y - 16381 log2 # +# cosh(X) := Fact * exp(Y'). # +# Exit. # +# # +# 5. (|X| > 16480 log2) sinh(X) must overflow. Return # +# Huge*Huge to generate overflow and an infinity with # +# the appropriate sign. Huge is the largest finite number # +# in extended format. Exit. # +# # +######################################################################### + +TWO16380: + long 0x7FFB0000,0x80000000,0x00000000,0x00000000 + + global scosh +scosh: + fmov.x (%a0),%fp0 # LOAD INPUT + + mov.l (%a0),%d1 + mov.w 4(%a0),%d1 + and.l &0x7FFFFFFF,%d1 + cmp.l %d1,&0x400CB167 + bgt.b COSHBIG + +#--THIS IS THE USUAL CASE, |X| < 16380 LOG2 +#--COSH(X) = (1/2) * ( EXP(X) + 1/EXP(X) ) + + fabs.x %fp0 # |X| + + mov.l %d0,-(%sp) + clr.l %d0 + fmovm.x &0x01,-(%sp) # save |X| to stack + lea (%sp),%a0 # pass ptr to |X| + bsr setox # FP0 IS EXP(|X|) + add.l &0xc,%sp # erase |X| from stack + fmul.s &0x3F000000,%fp0 # (1/2)EXP(|X|) + mov.l (%sp)+,%d0 + + fmov.s &0x3E800000,%fp1 # (1/4) + fdiv.x %fp0,%fp1 # 1/(2 EXP(|X|)) + + fmov.l %d0,%fpcr + mov.b &FADD_OP,%d1 # last inst is ADD + fadd.x %fp1,%fp0 + bra t_catch + +COSHBIG: + cmp.l %d1,&0x400CB2B3 + bgt.b COSHHUGE + + fabs.x %fp0 + fsub.d T1(%pc),%fp0 # (|X|-16381LOG2_LEAD) + fsub.d T2(%pc),%fp0 # |X| - 16381 LOG2, ACCURATE + + mov.l %d0,-(%sp) + clr.l %d0 + fmovm.x &0x01,-(%sp) # save fp0 to stack + lea (%sp),%a0 # pass ptr to fp0 + bsr setox + add.l &0xc,%sp # clear fp0 from stack + mov.l (%sp)+,%d0 + + fmov.l %d0,%fpcr + mov.b &FMUL_OP,%d1 # last inst is MUL + fmul.x TWO16380(%pc),%fp0 + bra t_catch + +COSHHUGE: + bra t_ovfl2 + + global scoshd +#--COSH(X) = 1 FOR DENORMALIZED X +scoshd: + fmov.s &0x3F800000,%fp0 + + fmov.l %d0,%fpcr + fadd.s &0x00800000,%fp0 + bra t_pinx2 + +######################################################################### +# ssinh(): computes the hyperbolic sine of a normalized input # +# ssinhd(): computes the hyperbolic sine of a denormalized input # +# # +# INPUT *************************************************************** # +# a0 = pointer to extended precision input # +# d0 = round precision,mode # +# # +# OUTPUT ************************************************************** # +# fp0 = sinh(X) # +# # +# ACCURACY and MONOTONICITY ******************************************* # +# The returned result is within 3 ulps in 64 significant bit, # +# i.e. within 0.5001 ulp to 53 bits if the result is subsequently # +# rounded to double precision. The result is provably monotonic # +# in double precision. # +# # +# ALGORITHM *********************************************************** # +# # +# SINH # +# 1. If |X| > 16380 log2, go to 3. # +# # +# 2. (|X| <= 16380 log2) Sinh(X) is obtained by the formula # +# y = |X|, sgn = sign(X), and z = expm1(Y), # +# sinh(X) = sgn*(1/2)*( z + z/(1+z) ). # +# Exit. # +# # +# 3. If |X| > 16480 log2, go to 5. # +# # +# 4. (16380 log2 < |X| <= 16480 log2) # +# sinh(X) = sign(X) * exp(|X|)/2. # +# However, invoking exp(|X|) may cause premature overflow. # +# Thus, we calculate sinh(X) as follows: # +# Y := |X| # +# sgn := sign(X) # +# sgnFact := sgn * 2**(16380) # +# Y' := Y - 16381 log2 # +# sinh(X) := sgnFact * exp(Y'). # +# Exit. # +# # +# 5. (|X| > 16480 log2) sinh(X) must overflow. Return # +# sign(X)*Huge*Huge to generate overflow and an infinity with # +# the appropriate sign. Huge is the largest finite number in # +# extended format. Exit. # +# # +######################################################################### + + global ssinh +ssinh: + fmov.x (%a0),%fp0 # LOAD INPUT + + mov.l (%a0),%d1 + mov.w 4(%a0),%d1 + mov.l %d1,%a1 # save (compacted) operand + and.l &0x7FFFFFFF,%d1 + cmp.l %d1,&0x400CB167 + bgt.b SINHBIG + +#--THIS IS THE USUAL CASE, |X| < 16380 LOG2 +#--Y = |X|, Z = EXPM1(Y), SINH(X) = SIGN(X)*(1/2)*( Z + Z/(1+Z) ) + + fabs.x %fp0 # Y = |X| + + movm.l &0x8040,-(%sp) # {a1/d0} + fmovm.x &0x01,-(%sp) # save Y on stack + lea (%sp),%a0 # pass ptr to Y + clr.l %d0 + bsr setoxm1 # FP0 IS Z = EXPM1(Y) + add.l &0xc,%sp # clear Y from stack + fmov.l &0,%fpcr + movm.l (%sp)+,&0x0201 # {a1/d0} + + fmov.x %fp0,%fp1 + fadd.s &0x3F800000,%fp1 # 1+Z + fmov.x %fp0,-(%sp) + fdiv.x %fp1,%fp0 # Z/(1+Z) + mov.l %a1,%d1 + and.l &0x80000000,%d1 + or.l &0x3F000000,%d1 + fadd.x (%sp)+,%fp0 + mov.l %d1,-(%sp) + + fmov.l %d0,%fpcr + mov.b &FMUL_OP,%d1 # last inst is MUL + fmul.s (%sp)+,%fp0 # last fp inst - possible exceptions set + bra t_catch + +SINHBIG: + cmp.l %d1,&0x400CB2B3 + bgt t_ovfl + fabs.x %fp0 + fsub.d T1(%pc),%fp0 # (|X|-16381LOG2_LEAD) + mov.l &0,-(%sp) + mov.l &0x80000000,-(%sp) + mov.l %a1,%d1 + and.l &0x80000000,%d1 + or.l &0x7FFB0000,%d1 + mov.l %d1,-(%sp) # EXTENDED FMT + fsub.d T2(%pc),%fp0 # |X| - 16381 LOG2, ACCURATE + + mov.l %d0,-(%sp) + clr.l %d0 + fmovm.x &0x01,-(%sp) # save fp0 on stack + lea (%sp),%a0 # pass ptr to fp0 + bsr setox + add.l &0xc,%sp # clear fp0 from stack + + mov.l (%sp)+,%d0 + fmov.l %d0,%fpcr + mov.b &FMUL_OP,%d1 # last inst is MUL + fmul.x (%sp)+,%fp0 # possible exception + bra t_catch + + global ssinhd +#--SINH(X) = X FOR DENORMALIZED X +ssinhd: + bra t_extdnrm + +######################################################################### +# stanh(): computes the hyperbolic tangent of a normalized input # +# stanhd(): computes the hyperbolic tangent of a denormalized input # +# # +# INPUT *************************************************************** # +# a0 = pointer to extended precision input # +# d0 = round precision,mode # +# # +# OUTPUT ************************************************************** # +# fp0 = tanh(X) # +# # +# ACCURACY and MONOTONICITY ******************************************* # +# The returned result is within 3 ulps in 64 significant bit, # +# i.e. within 0.5001 ulp to 53 bits if the result is subsequently # +# rounded to double precision. The result is provably monotonic # +# in double precision. # +# # +# ALGORITHM *********************************************************** # +# # +# TANH # +# 1. If |X| >= (5/2) log2 or |X| <= 2**(-40), go to 3. # +# # +# 2. (2**(-40) < |X| < (5/2) log2) Calculate tanh(X) by # +# sgn := sign(X), y := 2|X|, z := expm1(Y), and # +# tanh(X) = sgn*( z/(2+z) ). # +# Exit. # +# # +# 3. (|X| <= 2**(-40) or |X| >= (5/2) log2). If |X| < 1, # +# go to 7. # +# # +# 4. (|X| >= (5/2) log2) If |X| >= 50 log2, go to 6. # +# # +# 5. ((5/2) log2 <= |X| < 50 log2) Calculate tanh(X) by # +# sgn := sign(X), y := 2|X|, z := exp(Y), # +# tanh(X) = sgn - [ sgn*2/(1+z) ]. # +# Exit. # +# # +# 6. (|X| >= 50 log2) Tanh(X) = +-1 (round to nearest). Thus, we # +# calculate Tanh(X) by # +# sgn := sign(X), Tiny := 2**(-126), # +# tanh(X) := sgn - sgn*Tiny. # +# Exit. # +# # +# 7. (|X| < 2**(-40)). Tanh(X) = X. Exit. # +# # +######################################################################### + + set X,FP_SCR0 + set XFRAC,X+4 + + set SGN,L_SCR3 + + set V,FP_SCR0 + + global stanh +stanh: + fmov.x (%a0),%fp0 # LOAD INPUT + + fmov.x %fp0,X(%a6) + mov.l (%a0),%d1 + mov.w 4(%a0),%d1 + mov.l %d1,X(%a6) + and.l &0x7FFFFFFF,%d1 + cmp.l %d1, &0x3fd78000 # is |X| < 2^(-40)? + blt.w TANHBORS # yes + cmp.l %d1, &0x3fffddce # is |X| > (5/2)LOG2? + bgt.w TANHBORS # yes + +#--THIS IS THE USUAL CASE +#--Y = 2|X|, Z = EXPM1(Y), TANH(X) = SIGN(X) * Z / (Z+2). + + mov.l X(%a6),%d1 + mov.l %d1,SGN(%a6) + and.l &0x7FFF0000,%d1 + add.l &0x00010000,%d1 # EXPONENT OF 2|X| + mov.l %d1,X(%a6) + and.l &0x80000000,SGN(%a6) + fmov.x X(%a6),%fp0 # FP0 IS Y = 2|X| + + mov.l %d0,-(%sp) + clr.l %d0 + fmovm.x &0x1,-(%sp) # save Y on stack + lea (%sp),%a0 # pass ptr to Y + bsr setoxm1 # FP0 IS Z = EXPM1(Y) + add.l &0xc,%sp # clear Y from stack + mov.l (%sp)+,%d0 + + fmov.x %fp0,%fp1 + fadd.s &0x40000000,%fp1 # Z+2 + mov.l SGN(%a6),%d1 + fmov.x %fp1,V(%a6) + eor.l %d1,V(%a6) + + fmov.l %d0,%fpcr # restore users round prec,mode + fdiv.x V(%a6),%fp0 + bra t_inx2 + +TANHBORS: + cmp.l %d1,&0x3FFF8000 + blt.w TANHSM + + cmp.l %d1,&0x40048AA1 + bgt.w TANHHUGE + +#-- (5/2) LOG2 < |X| < 50 LOG2, +#--TANH(X) = 1 - (2/[EXP(2X)+1]). LET Y = 2|X|, SGN = SIGN(X), +#--TANH(X) = SGN - SGN*2/[EXP(Y)+1]. + + mov.l X(%a6),%d1 + mov.l %d1,SGN(%a6) + and.l &0x7FFF0000,%d1 + add.l &0x00010000,%d1 # EXPO OF 2|X| + mov.l %d1,X(%a6) # Y = 2|X| + and.l &0x80000000,SGN(%a6) + mov.l SGN(%a6),%d1 + fmov.x X(%a6),%fp0 # Y = 2|X| + + mov.l %d0,-(%sp) + clr.l %d0 + fmovm.x &0x01,-(%sp) # save Y on stack + lea (%sp),%a0 # pass ptr to Y + bsr setox # FP0 IS EXP(Y) + add.l &0xc,%sp # clear Y from stack + mov.l (%sp)+,%d0 + mov.l SGN(%a6),%d1 + fadd.s &0x3F800000,%fp0 # EXP(Y)+1 + + eor.l &0xC0000000,%d1 # -SIGN(X)*2 + fmov.s %d1,%fp1 # -SIGN(X)*2 IN SGL FMT + fdiv.x %fp0,%fp1 # -SIGN(X)2 / [EXP(Y)+1 ] + + mov.l SGN(%a6),%d1 + or.l &0x3F800000,%d1 # SGN + fmov.s %d1,%fp0 # SGN IN SGL FMT + + fmov.l %d0,%fpcr # restore users round prec,mode + mov.b &FADD_OP,%d1 # last inst is ADD + fadd.x %fp1,%fp0 + bra t_inx2 + +TANHSM: + fmov.l %d0,%fpcr # restore users round prec,mode + mov.b &FMOV_OP,%d1 # last inst is MOVE + fmov.x X(%a6),%fp0 # last inst - possible exception set + bra t_catch + +#---RETURN SGN(X) - SGN(X)EPS +TANHHUGE: + mov.l X(%a6),%d1 + and.l &0x80000000,%d1 + or.l &0x3F800000,%d1 + fmov.s %d1,%fp0 + and.l &0x80000000,%d1 + eor.l &0x80800000,%d1 # -SIGN(X)*EPS + + fmov.l %d0,%fpcr # restore users round prec,mode + fadd.s %d1,%fp0 + bra t_inx2 + + global stanhd +#--TANH(X) = X FOR DENORMALIZED X +stanhd: + bra t_extdnrm + +######################################################################### +# slogn(): computes the natural logarithm of a normalized input # +# slognd(): computes the natural logarithm of a denormalized input # +# slognp1(): computes the log(1+X) of a normalized input # +# slognp1d(): computes the log(1+X) of a denormalized input # +# # +# INPUT *************************************************************** # +# a0 = pointer to extended precision input # +# d0 = round precision,mode # +# # +# OUTPUT ************************************************************** # +# fp0 = log(X) or log(1+X) # +# # +# ACCURACY and MONOTONICITY ******************************************* # +# The returned result is within 2 ulps in 64 significant bit, # +# i.e. within 0.5001 ulp to 53 bits if the result is subsequently # +# rounded to double precision. The result is provably monotonic # +# in double precision. # +# # +# ALGORITHM *********************************************************** # +# LOGN: # +# Step 1. If |X-1| < 1/16, approximate log(X) by an odd # +# polynomial in u, where u = 2(X-1)/(X+1). Otherwise, # +# move on to Step 2. # +# # +# Step 2. X = 2**k * Y where 1 <= Y < 2. Define F to be the first # +# seven significant bits of Y plus 2**(-7), i.e. # +# F = 1.xxxxxx1 in base 2 where the six "x" match those # +# of Y. Note that |Y-F| <= 2**(-7). # +# # +# Step 3. Define u = (Y-F)/F. Approximate log(1+u) by a # +# polynomial in u, log(1+u) = poly. # +# # +# Step 4. Reconstruct # +# log(X) = log( 2**k * Y ) = k*log(2) + log(F) + log(1+u) # +# by k*log(2) + (log(F) + poly). The values of log(F) are # +# calculated beforehand and stored in the program. # +# # +# lognp1: # +# Step 1: If |X| < 1/16, approximate log(1+X) by an odd # +# polynomial in u where u = 2X/(2+X). Otherwise, move on # +# to Step 2. # +# # +# Step 2: Let 1+X = 2**k * Y, where 1 <= Y < 2. Define F as done # +# in Step 2 of the algorithm for LOGN and compute # +# log(1+X) as k*log(2) + log(F) + poly where poly # +# approximates log(1+u), u = (Y-F)/F. # +# # +# Implementation Notes: # +# Note 1. There are 64 different possible values for F, thus 64 # +# log(F)'s need to be tabulated. Moreover, the values of # +# 1/F are also tabulated so that the division in (Y-F)/F # +# can be performed by a multiplication. # +# # +# Note 2. In Step 2 of lognp1, in order to preserved accuracy, # +# the value Y-F has to be calculated carefully when # +# 1/2 <= X < 3/2. # +# # +# Note 3. To fully exploit the pipeline, polynomials are usually # +# separated into two parts evaluated independently before # +# being added up. # +# # +######################################################################### +LOGOF2: + long 0x3FFE0000,0xB17217F7,0xD1CF79AC,0x00000000 + +one: + long 0x3F800000 +zero: + long 0x00000000 +infty: + long 0x7F800000 +negone: + long 0xBF800000 + +LOGA6: + long 0x3FC2499A,0xB5E4040B +LOGA5: + long 0xBFC555B5,0x848CB7DB + +LOGA4: + long 0x3FC99999,0x987D8730 +LOGA3: + long 0xBFCFFFFF,0xFF6F7E97 + +LOGA2: + long 0x3FD55555,0x555555A4 +LOGA1: + long 0xBFE00000,0x00000008 + +LOGB5: + long 0x3F175496,0xADD7DAD6 +LOGB4: + long 0x3F3C71C2,0xFE80C7E0 + +LOGB3: + long 0x3F624924,0x928BCCFF +LOGB2: + long 0x3F899999,0x999995EC + +LOGB1: + long 0x3FB55555,0x55555555 +TWO: + long 0x40000000,0x00000000 + +LTHOLD: + long 0x3f990000,0x80000000,0x00000000,0x00000000 + +LOGTBL: + long 0x3FFE0000,0xFE03F80F,0xE03F80FE,0x00000000 + long 0x3FF70000,0xFF015358,0x833C47E2,0x00000000 + long 0x3FFE0000,0xFA232CF2,0x52138AC0,0x00000000 + long 0x3FF90000,0xBDC8D83E,0xAD88D549,0x00000000 + long 0x3FFE0000,0xF6603D98,0x0F6603DA,0x00000000 + long 0x3FFA0000,0x9CF43DCF,0xF5EAFD48,0x00000000 + long 0x3FFE0000,0xF2B9D648,0x0F2B9D65,0x00000000 + long 0x3FFA0000,0xDA16EB88,0xCB8DF614,0x00000000 + long 0x3FFE0000,0xEF2EB71F,0xC4345238,0x00000000 + long 0x3FFB0000,0x8B29B775,0x1BD70743,0x00000000 + long 0x3FFE0000,0xEBBDB2A5,0xC1619C8C,0x00000000 + long 0x3FFB0000,0xA8D839F8,0x30C1FB49,0x00000000 + long 0x3FFE0000,0xE865AC7B,0x7603A197,0x00000000 + long 0x3FFB0000,0xC61A2EB1,0x8CD907AD,0x00000000 + long 0x3FFE0000,0xE525982A,0xF70C880E,0x00000000 + long 0x3FFB0000,0xE2F2A47A,0xDE3A18AF,0x00000000 + long 0x3FFE0000,0xE1FC780E,0x1FC780E2,0x00000000 + long 0x3FFB0000,0xFF64898E,0xDF55D551,0x00000000 + long 0x3FFE0000,0xDEE95C4C,0xA037BA57,0x00000000 + long 0x3FFC0000,0x8DB956A9,0x7B3D0148,0x00000000 + long 0x3FFE0000,0xDBEB61EE,0xD19C5958,0x00000000 + long 0x3FFC0000,0x9B8FE100,0xF47BA1DE,0x00000000 + long 0x3FFE0000,0xD901B203,0x6406C80E,0x00000000 + long 0x3FFC0000,0xA9372F1D,0x0DA1BD17,0x00000000 + long 0x3FFE0000,0xD62B80D6,0x2B80D62C,0x00000000 + long 0x3FFC0000,0xB6B07F38,0xCE90E46B,0x00000000 + long 0x3FFE0000,0xD3680D36,0x80D3680D,0x00000000 + long 0x3FFC0000,0xC3FD0329,0x06488481,0x00000000 + long 0x3FFE0000,0xD0B69FCB,0xD2580D0B,0x00000000 + long 0x3FFC0000,0xD11DE0FF,0x15AB18CA,0x00000000 + long 0x3FFE0000,0xCE168A77,0x25080CE1,0x00000000 + long 0x3FFC0000,0xDE1433A1,0x6C66B150,0x00000000 + long 0x3FFE0000,0xCB8727C0,0x65C393E0,0x00000000 + long 0x3FFC0000,0xEAE10B5A,0x7DDC8ADD,0x00000000 + long 0x3FFE0000,0xC907DA4E,0x871146AD,0x00000000 + long 0x3FFC0000,0xF7856E5E,0xE2C9B291,0x00000000 + long 0x3FFE0000,0xC6980C69,0x80C6980C,0x00000000 + long 0x3FFD0000,0x82012CA5,0xA68206D7,0x00000000 + long 0x3FFE0000,0xC4372F85,0x5D824CA6,0x00000000 + long 0x3FFD0000,0x882C5FCD,0x7256A8C5,0x00000000 + long 0x3FFE0000,0xC1E4BBD5,0x95F6E947,0x00000000 + long 0x3FFD0000,0x8E44C60B,0x4CCFD7DE,0x00000000 + long 0x3FFE0000,0xBFA02FE8,0x0BFA02FF,0x00000000 + long 0x3FFD0000,0x944AD09E,0xF4351AF6,0x00000000 + long 0x3FFE0000,0xBD691047,0x07661AA3,0x00000000 + long 0x3FFD0000,0x9A3EECD4,0xC3EAA6B2,0x00000000 + long 0x3FFE0000,0xBB3EE721,0xA54D880C,0x00000000 + long 0x3FFD0000,0xA0218434,0x353F1DE8,0x00000000 + long 0x3FFE0000,0xB92143FA,0x36F5E02E,0x00000000 + long 0x3FFD0000,0xA5F2FCAB,0xBBC506DA,0x00000000 + long 0x3FFE0000,0xB70FBB5A,0x19BE3659,0x00000000 + long 0x3FFD0000,0xABB3B8BA,0x2AD362A5,0x00000000 + long 0x3FFE0000,0xB509E68A,0x9B94821F,0x00000000 + long 0x3FFD0000,0xB1641795,0xCE3CA97B,0x00000000 + long 0x3FFE0000,0xB30F6352,0x8917C80B,0x00000000 + long 0x3FFD0000,0xB7047551,0x5D0F1C61,0x00000000 + long 0x3FFE0000,0xB11FD3B8,0x0B11FD3C,0x00000000 + long 0x3FFD0000,0xBC952AFE,0xEA3D13E1,0x00000000 + long 0x3FFE0000,0xAF3ADDC6,0x80AF3ADE,0x00000000 + long 0x3FFD0000,0xC2168ED0,0xF458BA4A,0x00000000 + long 0x3FFE0000,0xAD602B58,0x0AD602B6,0x00000000 + long 0x3FFD0000,0xC788F439,0xB3163BF1,0x00000000 + long 0x3FFE0000,0xAB8F69E2,0x8359CD11,0x00000000 + long 0x3FFD0000,0xCCECAC08,0xBF04565D,0x00000000 + long 0x3FFE0000,0xA9C84A47,0xA07F5638,0x00000000 + long 0x3FFD0000,0xD2420487,0x2DD85160,0x00000000 + long 0x3FFE0000,0xA80A80A8,0x0A80A80B,0x00000000 + long 0x3FFD0000,0xD7894992,0x3BC3588A,0x00000000 + long 0x3FFE0000,0xA655C439,0x2D7B73A8,0x00000000 + long 0x3FFD0000,0xDCC2C4B4,0x9887DACC,0x00000000 + long 0x3FFE0000,0xA4A9CF1D,0x96833751,0x00000000 + long 0x3FFD0000,0xE1EEBD3E,0x6D6A6B9E,0x00000000 + long 0x3FFE0000,0xA3065E3F,0xAE7CD0E0,0x00000000 + long 0x3FFD0000,0xE70D785C,0x2F9F5BDC,0x00000000 + long 0x3FFE0000,0xA16B312E,0xA8FC377D,0x00000000 + long 0x3FFD0000,0xEC1F392C,0x5179F283,0x00000000 + long 0x3FFE0000,0x9FD809FD,0x809FD80A,0x00000000 + long 0x3FFD0000,0xF12440D3,0xE36130E6,0x00000000 + long 0x3FFE0000,0x9E4CAD23,0xDD5F3A20,0x00000000 + long 0x3FFD0000,0xF61CCE92,0x346600BB,0x00000000 + long 0x3FFE0000,0x9CC8E160,0xC3FB19B9,0x00000000 + long 0x3FFD0000,0xFB091FD3,0x8145630A,0x00000000 + long 0x3FFE0000,0x9B4C6F9E,0xF03A3CAA,0x00000000 + long 0x3FFD0000,0xFFE97042,0xBFA4C2AD,0x00000000 + long 0x3FFE0000,0x99D722DA,0xBDE58F06,0x00000000 + long 0x3FFE0000,0x825EFCED,0x49369330,0x00000000 + long 0x3FFE0000,0x9868C809,0x868C8098,0x00000000 + long 0x3FFE0000,0x84C37A7A,0xB9A905C9,0x00000000 + long 0x3FFE0000,0x97012E02,0x5C04B809,0x00000000 + long 0x3FFE0000,0x87224C2E,0x8E645FB7,0x00000000 + long 0x3FFE0000,0x95A02568,0x095A0257,0x00000000 + long 0x3FFE0000,0x897B8CAC,0x9F7DE298,0x00000000 + long 0x3FFE0000,0x94458094,0x45809446,0x00000000 + long 0x3FFE0000,0x8BCF55DE,0xC4CD05FE,0x00000000 + long 0x3FFE0000,0x92F11384,0x0497889C,0x00000000 + long 0x3FFE0000,0x8E1DC0FB,0x89E125E5,0x00000000 + long 0x3FFE0000,0x91A2B3C4,0xD5E6F809,0x00000000 + long 0x3FFE0000,0x9066E68C,0x955B6C9B,0x00000000 + long 0x3FFE0000,0x905A3863,0x3E06C43B,0x00000000 + long 0x3FFE0000,0x92AADE74,0xC7BE59E0,0x00000000 + long 0x3FFE0000,0x8F1779D9,0xFDC3A219,0x00000000 + long 0x3FFE0000,0x94E9BFF6,0x15845643,0x00000000 + long 0x3FFE0000,0x8DDA5202,0x37694809,0x00000000 + long 0x3FFE0000,0x9723A1B7,0x20134203,0x00000000 + long 0x3FFE0000,0x8CA29C04,0x6514E023,0x00000000 + long 0x3FFE0000,0x995899C8,0x90EB8990,0x00000000 + long 0x3FFE0000,0x8B70344A,0x139BC75A,0x00000000 + long 0x3FFE0000,0x9B88BDAA,0x3A3DAE2F,0x00000000 + long 0x3FFE0000,0x8A42F870,0x5669DB46,0x00000000 + long 0x3FFE0000,0x9DB4224F,0xFFE1157C,0x00000000 + long 0x3FFE0000,0x891AC73A,0xE9819B50,0x00000000 + long 0x3FFE0000,0x9FDADC26,0x8B7A12DA,0x00000000 + long 0x3FFE0000,0x87F78087,0xF78087F8,0x00000000 + long 0x3FFE0000,0xA1FCFF17,0xCE733BD4,0x00000000 + long 0x3FFE0000,0x86D90544,0x7A34ACC6,0x00000000 + long 0x3FFE0000,0xA41A9E8F,0x5446FB9F,0x00000000 + long 0x3FFE0000,0x85BF3761,0x2CEE3C9B,0x00000000 + long 0x3FFE0000,0xA633CD7E,0x6771CD8B,0x00000000 + long 0x3FFE0000,0x84A9F9C8,0x084A9F9D,0x00000000 + long 0x3FFE0000,0xA8489E60,0x0B435A5E,0x00000000 + long 0x3FFE0000,0x83993052,0x3FBE3368,0x00000000 + long 0x3FFE0000,0xAA59233C,0xCCA4BD49,0x00000000 + long 0x3FFE0000,0x828CBFBE,0xB9A020A3,0x00000000 + long 0x3FFE0000,0xAC656DAE,0x6BCC4985,0x00000000 + long 0x3FFE0000,0x81848DA8,0xFAF0D277,0x00000000 + long 0x3FFE0000,0xAE6D8EE3,0x60BB2468,0x00000000 + long 0x3FFE0000,0x80808080,0x80808081,0x00000000 + long 0x3FFE0000,0xB07197A2,0x3C46C654,0x00000000 + + set ADJK,L_SCR1 + + set X,FP_SCR0 + set XDCARE,X+2 + set XFRAC,X+4 + + set F,FP_SCR1 + set FFRAC,F+4 + + set KLOG2,FP_SCR0 + + set SAVEU,FP_SCR0 + + global slogn +#--ENTRY POINT FOR LOG(X) FOR X FINITE, NON-ZERO, NOT NAN'S +slogn: + fmov.x (%a0),%fp0 # LOAD INPUT + mov.l &0x00000000,ADJK(%a6) + +LOGBGN: +#--FPCR SAVED AND CLEARED, INPUT IS 2^(ADJK)*FP0, FP0 CONTAINS +#--A FINITE, NON-ZERO, NORMALIZED NUMBER. + + mov.l (%a0),%d1 + mov.w 4(%a0),%d1 + + mov.l (%a0),X(%a6) + mov.l 4(%a0),X+4(%a6) + mov.l 8(%a0),X+8(%a6) + + cmp.l %d1,&0 # CHECK IF X IS NEGATIVE + blt.w LOGNEG # LOG OF NEGATIVE ARGUMENT IS INVALID +# X IS POSITIVE, CHECK IF X IS NEAR 1 + cmp.l %d1,&0x3ffef07d # IS X < 15/16? + blt.b LOGMAIN # YES + cmp.l %d1,&0x3fff8841 # IS X > 17/16? + ble.w LOGNEAR1 # NO + +LOGMAIN: +#--THIS SHOULD BE THE USUAL CASE, X NOT VERY CLOSE TO 1 + +#--X = 2^(K) * Y, 1 <= Y < 2. THUS, Y = 1.XXXXXXXX....XX IN BINARY. +#--WE DEFINE F = 1.XXXXXX1, I.E. FIRST 7 BITS OF Y AND ATTACH A 1. +#--THE IDEA IS THAT LOG(X) = K*LOG2 + LOG(Y) +#-- = K*LOG2 + LOG(F) + LOG(1 + (Y-F)/F). +#--NOTE THAT U = (Y-F)/F IS VERY SMALL AND THUS APPROXIMATING +#--LOG(1+U) CAN BE VERY EFFICIENT. +#--ALSO NOTE THAT THE VALUE 1/F IS STORED IN A TABLE SO THAT NO +#--DIVISION IS NEEDED TO CALCULATE (Y-F)/F. + +#--GET K, Y, F, AND ADDRESS OF 1/F. + asr.l &8,%d1 + asr.l &8,%d1 # SHIFTED 16 BITS, BIASED EXPO. OF X + sub.l &0x3FFF,%d1 # THIS IS K + add.l ADJK(%a6),%d1 # ADJUST K, ORIGINAL INPUT MAY BE DENORM. + lea LOGTBL(%pc),%a0 # BASE ADDRESS OF 1/F AND LOG(F) + fmov.l %d1,%fp1 # CONVERT K TO FLOATING-POINT FORMAT + +#--WHILE THE CONVERSION IS GOING ON, WE GET F AND ADDRESS OF 1/F + mov.l &0x3FFF0000,X(%a6) # X IS NOW Y, I.E. 2^(-K)*X + mov.l XFRAC(%a6),FFRAC(%a6) + and.l &0xFE000000,FFRAC(%a6) # FIRST 7 BITS OF Y + or.l &0x01000000,FFRAC(%a6) # GET F: ATTACH A 1 AT THE EIGHTH BIT + mov.l FFRAC(%a6),%d1 # READY TO GET ADDRESS OF 1/F + and.l &0x7E000000,%d1 + asr.l &8,%d1 + asr.l &8,%d1 + asr.l &4,%d1 # SHIFTED 20, D0 IS THE DISPLACEMENT + add.l %d1,%a0 # A0 IS THE ADDRESS FOR 1/F + + fmov.x X(%a6),%fp0 + mov.l &0x3fff0000,F(%a6) + clr.l F+8(%a6) + fsub.x F(%a6),%fp0 # Y-F + fmovm.x &0xc,-(%sp) # SAVE FP2-3 WHILE FP0 IS NOT READY +#--SUMMARY: FP0 IS Y-F, A0 IS ADDRESS OF 1/F, FP1 IS K +#--REGISTERS SAVED: FPCR, FP1, FP2 + +LP1CONT1: +#--AN RE-ENTRY POINT FOR LOGNP1 + fmul.x (%a0),%fp0 # FP0 IS U = (Y-F)/F + fmul.x LOGOF2(%pc),%fp1 # GET K*LOG2 WHILE FP0 IS NOT READY + fmov.x %fp0,%fp2 + fmul.x %fp2,%fp2 # FP2 IS V=U*U + fmov.x %fp1,KLOG2(%a6) # PUT K*LOG2 IN MEMEORY, FREE FP1 + +#--LOG(1+U) IS APPROXIMATED BY +#--U + V*(A1+U*(A2+U*(A3+U*(A4+U*(A5+U*A6))))) WHICH IS +#--[U + V*(A1+V*(A3+V*A5))] + [U*V*(A2+V*(A4+V*A6))] + + fmov.x %fp2,%fp3 + fmov.x %fp2,%fp1 + + fmul.d LOGA6(%pc),%fp1 # V*A6 + fmul.d LOGA5(%pc),%fp2 # V*A5 + + fadd.d LOGA4(%pc),%fp1 # A4+V*A6 + fadd.d LOGA3(%pc),%fp2 # A3+V*A5 + + fmul.x %fp3,%fp1 # V*(A4+V*A6) + fmul.x %fp3,%fp2 # V*(A3+V*A5) + + fadd.d LOGA2(%pc),%fp1 # A2+V*(A4+V*A6) + fadd.d LOGA1(%pc),%fp2 # A1+V*(A3+V*A5) + + fmul.x %fp3,%fp1 # V*(A2+V*(A4+V*A6)) + add.l &16,%a0 # ADDRESS OF LOG(F) + fmul.x %fp3,%fp2 # V*(A1+V*(A3+V*A5)) + + fmul.x %fp0,%fp1 # U*V*(A2+V*(A4+V*A6)) + fadd.x %fp2,%fp0 # U+V*(A1+V*(A3+V*A5)) + + fadd.x (%a0),%fp1 # LOG(F)+U*V*(A2+V*(A4+V*A6)) + fmovm.x (%sp)+,&0x30 # RESTORE FP2-3 + fadd.x %fp1,%fp0 # FP0 IS LOG(F) + LOG(1+U) + + fmov.l %d0,%fpcr + fadd.x KLOG2(%a6),%fp0 # FINAL ADD + bra t_inx2 + + +LOGNEAR1: + +# if the input is exactly equal to one, then exit through ld_pzero. +# if these 2 lines weren't here, the correct answer would be returned +# but the INEX2 bit would be set. + fcmp.b %fp0,&0x1 # is it equal to one? + fbeq.l ld_pzero # yes + +#--REGISTERS SAVED: FPCR, FP1. FP0 CONTAINS THE INPUT. + fmov.x %fp0,%fp1 + fsub.s one(%pc),%fp1 # FP1 IS X-1 + fadd.s one(%pc),%fp0 # FP0 IS X+1 + fadd.x %fp1,%fp1 # FP1 IS 2(X-1) +#--LOG(X) = LOG(1+U/2)-LOG(1-U/2) WHICH IS AN ODD POLYNOMIAL +#--IN U, U = 2(X-1)/(X+1) = FP1/FP0 + +LP1CONT2: +#--THIS IS AN RE-ENTRY POINT FOR LOGNP1 + fdiv.x %fp0,%fp1 # FP1 IS U + fmovm.x &0xc,-(%sp) # SAVE FP2-3 +#--REGISTERS SAVED ARE NOW FPCR,FP1,FP2,FP3 +#--LET V=U*U, W=V*V, CALCULATE +#--U + U*V*(B1 + V*(B2 + V*(B3 + V*(B4 + V*B5)))) BY +#--U + U*V*( [B1 + W*(B3 + W*B5)] + [V*(B2 + W*B4)] ) + fmov.x %fp1,%fp0 + fmul.x %fp0,%fp0 # FP0 IS V + fmov.x %fp1,SAVEU(%a6) # STORE U IN MEMORY, FREE FP1 + fmov.x %fp0,%fp1 + fmul.x %fp1,%fp1 # FP1 IS W + + fmov.d LOGB5(%pc),%fp3 + fmov.d LOGB4(%pc),%fp2 + + fmul.x %fp1,%fp3 # W*B5 + fmul.x %fp1,%fp2 # W*B4 + + fadd.d LOGB3(%pc),%fp3 # B3+W*B5 + fadd.d LOGB2(%pc),%fp2 # B2+W*B4 + + fmul.x %fp3,%fp1 # W*(B3+W*B5), FP3 RELEASED + + fmul.x %fp0,%fp2 # V*(B2+W*B4) + + fadd.d LOGB1(%pc),%fp1 # B1+W*(B3+W*B5) + fmul.x SAVEU(%a6),%fp0 # FP0 IS U*V + + fadd.x %fp2,%fp1 # B1+W*(B3+W*B5) + V*(B2+W*B4), FP2 RELEASED + fmovm.x (%sp)+,&0x30 # FP2-3 RESTORED + + fmul.x %fp1,%fp0 # U*V*( [B1+W*(B3+W*B5)] + [V*(B2+W*B4)] ) + + fmov.l %d0,%fpcr + fadd.x SAVEU(%a6),%fp0 + bra t_inx2 + +#--REGISTERS SAVED FPCR. LOG(-VE) IS INVALID +LOGNEG: + bra t_operr + + global slognd +slognd: +#--ENTRY POINT FOR LOG(X) FOR DENORMALIZED INPUT + + mov.l &-100,ADJK(%a6) # INPUT = 2^(ADJK) * FP0 + +#----normalize the input value by left shifting k bits (k to be determined +#----below), adjusting exponent and storing -k to ADJK +#----the value TWOTO100 is no longer needed. +#----Note that this code assumes the denormalized input is NON-ZERO. + + movm.l &0x3f00,-(%sp) # save some registers {d2-d7} + mov.l (%a0),%d3 # D3 is exponent of smallest norm. # + mov.l 4(%a0),%d4 + mov.l 8(%a0),%d5 # (D4,D5) is (Hi_X,Lo_X) + clr.l %d2 # D2 used for holding K + + tst.l %d4 + bne.b Hi_not0 + +Hi_0: + mov.l %d5,%d4 + clr.l %d5 + mov.l &32,%d2 + clr.l %d6 + bfffo %d4{&0:&32},%d6 + lsl.l %d6,%d4 + add.l %d6,%d2 # (D3,D4,D5) is normalized + + mov.l %d3,X(%a6) + mov.l %d4,XFRAC(%a6) + mov.l %d5,XFRAC+4(%a6) + neg.l %d2 + mov.l %d2,ADJK(%a6) + fmov.x X(%a6),%fp0 + movm.l (%sp)+,&0xfc # restore registers {d2-d7} + lea X(%a6),%a0 + bra.w LOGBGN # begin regular log(X) + +Hi_not0: + clr.l %d6 + bfffo %d4{&0:&32},%d6 # find first 1 + mov.l %d6,%d2 # get k + lsl.l %d6,%d4 + mov.l %d5,%d7 # a copy of D5 + lsl.l %d6,%d5 + neg.l %d6 + add.l &32,%d6 + lsr.l %d6,%d7 + or.l %d7,%d4 # (D3,D4,D5) normalized + + mov.l %d3,X(%a6) + mov.l %d4,XFRAC(%a6) + mov.l %d5,XFRAC+4(%a6) + neg.l %d2 + mov.l %d2,ADJK(%a6) + fmov.x X(%a6),%fp0 + movm.l (%sp)+,&0xfc # restore registers {d2-d7} + lea X(%a6),%a0 + bra.w LOGBGN # begin regular log(X) + + global slognp1 +#--ENTRY POINT FOR LOG(1+X) FOR X FINITE, NON-ZERO, NOT NAN'S +slognp1: + fmov.x (%a0),%fp0 # LOAD INPUT + fabs.x %fp0 # test magnitude + fcmp.x %fp0,LTHOLD(%pc) # compare with min threshold + fbgt.w LP1REAL # if greater, continue + fmov.l %d0,%fpcr + mov.b &FMOV_OP,%d1 # last inst is MOVE + fmov.x (%a0),%fp0 # return signed argument + bra t_catch + +LP1REAL: + fmov.x (%a0),%fp0 # LOAD INPUT + mov.l &0x00000000,ADJK(%a6) + fmov.x %fp0,%fp1 # FP1 IS INPUT Z + fadd.s one(%pc),%fp0 # X := ROUND(1+Z) + fmov.x %fp0,X(%a6) + mov.w XFRAC(%a6),XDCARE(%a6) + mov.l X(%a6),%d1 + cmp.l %d1,&0 + ble.w LP1NEG0 # LOG OF ZERO OR -VE + cmp.l %d1,&0x3ffe8000 # IS BOUNDS [1/2,3/2]? + blt.w LOGMAIN + cmp.l %d1,&0x3fffc000 + bgt.w LOGMAIN +#--IF 1+Z > 3/2 OR 1+Z < 1/2, THEN X, WHICH IS ROUNDING 1+Z, +#--CONTAINS AT LEAST 63 BITS OF INFORMATION OF Z. IN THAT CASE, +#--SIMPLY INVOKE LOG(X) FOR LOG(1+Z). + +LP1NEAR1: +#--NEXT SEE IF EXP(-1/16) < X < EXP(1/16) + cmp.l %d1,&0x3ffef07d + blt.w LP1CARE + cmp.l %d1,&0x3fff8841 + bgt.w LP1CARE + +LP1ONE16: +#--EXP(-1/16) < X < EXP(1/16). LOG(1+Z) = LOG(1+U/2) - LOG(1-U/2) +#--WHERE U = 2Z/(2+Z) = 2Z/(1+X). + fadd.x %fp1,%fp1 # FP1 IS 2Z + fadd.s one(%pc),%fp0 # FP0 IS 1+X +#--U = FP1/FP0 + bra.w LP1CONT2 + +LP1CARE: +#--HERE WE USE THE USUAL TABLE DRIVEN APPROACH. CARE HAS TO BE +#--TAKEN BECAUSE 1+Z CAN HAVE 67 BITS OF INFORMATION AND WE MUST +#--PRESERVE ALL THE INFORMATION. BECAUSE 1+Z IS IN [1/2,3/2], +#--THERE ARE ONLY TWO CASES. +#--CASE 1: 1+Z < 1, THEN K = -1 AND Y-F = (2-F) + 2Z +#--CASE 2: 1+Z > 1, THEN K = 0 AND Y-F = (1-F) + Z +#--ON RETURNING TO LP1CONT1, WE MUST HAVE K IN FP1, ADDRESS OF +#--(1/F) IN A0, Y-F IN FP0, AND FP2 SAVED. + + mov.l XFRAC(%a6),FFRAC(%a6) + and.l &0xFE000000,FFRAC(%a6) + or.l &0x01000000,FFRAC(%a6) # F OBTAINED + cmp.l %d1,&0x3FFF8000 # SEE IF 1+Z > 1 + bge.b KISZERO + +KISNEG1: + fmov.s TWO(%pc),%fp0 + mov.l &0x3fff0000,F(%a6) + clr.l F+8(%a6) + fsub.x F(%a6),%fp0 # 2-F + mov.l FFRAC(%a6),%d1 + and.l &0x7E000000,%d1 + asr.l &8,%d1 + asr.l &8,%d1 + asr.l &4,%d1 # D0 CONTAINS DISPLACEMENT FOR 1/F + fadd.x %fp1,%fp1 # GET 2Z + fmovm.x &0xc,-(%sp) # SAVE FP2 {%fp2/%fp3} + fadd.x %fp1,%fp0 # FP0 IS Y-F = (2-F)+2Z + lea LOGTBL(%pc),%a0 # A0 IS ADDRESS OF 1/F + add.l %d1,%a0 + fmov.s negone(%pc),%fp1 # FP1 IS K = -1 + bra.w LP1CONT1 + +KISZERO: + fmov.s one(%pc),%fp0 + mov.l &0x3fff0000,F(%a6) + clr.l F+8(%a6) + fsub.x F(%a6),%fp0 # 1-F + mov.l FFRAC(%a6),%d1 + and.l &0x7E000000,%d1 + asr.l &8,%d1 + asr.l &8,%d1 + asr.l &4,%d1 + fadd.x %fp1,%fp0 # FP0 IS Y-F + fmovm.x &0xc,-(%sp) # FP2 SAVED {%fp2/%fp3} + lea LOGTBL(%pc),%a0 + add.l %d1,%a0 # A0 IS ADDRESS OF 1/F + fmov.s zero(%pc),%fp1 # FP1 IS K = 0 + bra.w LP1CONT1 + +LP1NEG0: +#--FPCR SAVED. D0 IS X IN COMPACT FORM. + cmp.l %d1,&0 + blt.b LP1NEG +LP1ZERO: + fmov.s negone(%pc),%fp0 + + fmov.l %d0,%fpcr + bra t_dz + +LP1NEG: + fmov.s zero(%pc),%fp0 + + fmov.l %d0,%fpcr + bra t_operr + + global slognp1d +#--ENTRY POINT FOR LOG(1+Z) FOR DENORMALIZED INPUT +# Simply return the denorm +slognp1d: + bra t_extdnrm + +######################################################################### +# satanh(): computes the inverse hyperbolic tangent of a norm input # +# satanhd(): computes the inverse hyperbolic tangent of a denorm input # +# # +# INPUT *************************************************************** # +# a0 = pointer to extended precision input # +# d0 = round precision,mode # +# # +# OUTPUT ************************************************************** # +# fp0 = arctanh(X) # +# # +# ACCURACY and MONOTONICITY ******************************************* # +# The returned result is within 3 ulps in 64 significant bit, # +# i.e. within 0.5001 ulp to 53 bits if the result is subsequently # +# rounded to double precision. The result is provably monotonic # +# in double precision. # +# # +# ALGORITHM *********************************************************** # +# # +# ATANH # +# 1. If |X| >= 1, go to 3. # +# # +# 2. (|X| < 1) Calculate atanh(X) by # +# sgn := sign(X) # +# y := |X| # +# z := 2y/(1-y) # +# atanh(X) := sgn * (1/2) * logp1(z) # +# Exit. # +# # +# 3. If |X| > 1, go to 5. # +# # +# 4. (|X| = 1) Generate infinity with an appropriate sign and # +# divide-by-zero by # +# sgn := sign(X) # +# atan(X) := sgn / (+0). # +# Exit. # +# # +# 5. (|X| > 1) Generate an invalid operation by 0 * infinity. # +# Exit. # +# # +######################################################################### + + global satanh +satanh: + mov.l (%a0),%d1 + mov.w 4(%a0),%d1 + and.l &0x7FFFFFFF,%d1 + cmp.l %d1,&0x3FFF8000 + bge.b ATANHBIG + +#--THIS IS THE USUAL CASE, |X| < 1 +#--Y = |X|, Z = 2Y/(1-Y), ATANH(X) = SIGN(X) * (1/2) * LOG1P(Z). + + fabs.x (%a0),%fp0 # Y = |X| + fmov.x %fp0,%fp1 + fneg.x %fp1 # -Y + fadd.x %fp0,%fp0 # 2Y + fadd.s &0x3F800000,%fp1 # 1-Y + fdiv.x %fp1,%fp0 # 2Y/(1-Y) + mov.l (%a0),%d1 + and.l &0x80000000,%d1 + or.l &0x3F000000,%d1 # SIGN(X)*HALF + mov.l %d1,-(%sp) + + mov.l %d0,-(%sp) # save rnd prec,mode + clr.l %d0 # pass ext prec,RN + fmovm.x &0x01,-(%sp) # save Z on stack + lea (%sp),%a0 # pass ptr to Z + bsr slognp1 # LOG1P(Z) + add.l &0xc,%sp # clear Z from stack + + mov.l (%sp)+,%d0 # fetch old prec,mode + fmov.l %d0,%fpcr # load it + mov.b &FMUL_OP,%d1 # last inst is MUL + fmul.s (%sp)+,%fp0 + bra t_catch + +ATANHBIG: + fabs.x (%a0),%fp0 # |X| + fcmp.s %fp0,&0x3F800000 + fbgt t_operr + bra t_dz + + global satanhd +#--ATANH(X) = X FOR DENORMALIZED X +satanhd: + bra t_extdnrm + +######################################################################### +# slog10(): computes the base-10 logarithm of a normalized input # +# slog10d(): computes the base-10 logarithm of a denormalized input # +# slog2(): computes the base-2 logarithm of a normalized input # +# slog2d(): computes the base-2 logarithm of a denormalized input # +# # +# INPUT *************************************************************** # +# a0 = pointer to extended precision input # +# d0 = round precision,mode # +# # +# OUTPUT ************************************************************** # +# fp0 = log_10(X) or log_2(X) # +# # +# ACCURACY and MONOTONICITY ******************************************* # +# The returned result is within 1.7 ulps in 64 significant bit, # +# i.e. within 0.5003 ulp to 53 bits if the result is subsequently # +# rounded to double precision. The result is provably monotonic # +# in double precision. # +# # +# ALGORITHM *********************************************************** # +# # +# slog10d: # +# # +# Step 0. If X < 0, create a NaN and raise the invalid operation # +# flag. Otherwise, save FPCR in D1; set FpCR to default. # +# Notes: Default means round-to-nearest mode, no floating-point # +# traps, and precision control = double extended. # +# # +# Step 1. Call slognd to obtain Y = log(X), the natural log of X. # +# Notes: Even if X is denormalized, log(X) is always normalized. # +# # +# Step 2. Compute log_10(X) = log(X) * (1/log(10)). # +# 2.1 Restore the user FPCR # +# 2.2 Return ans := Y * INV_L10. # +# # +# slog10: # +# # +# Step 0. If X < 0, create a NaN and raise the invalid operation # +# flag. Otherwise, save FPCR in D1; set FpCR to default. # +# Notes: Default means round-to-nearest mode, no floating-point # +# traps, and precision control = double extended. # +# # +# Step 1. Call sLogN to obtain Y = log(X), the natural log of X. # +# # +# Step 2. Compute log_10(X) = log(X) * (1/log(10)). # +# 2.1 Restore the user FPCR # +# 2.2 Return ans := Y * INV_L10. # +# # +# sLog2d: # +# # +# Step 0. If X < 0, create a NaN and raise the invalid operation # +# flag. Otherwise, save FPCR in D1; set FpCR to default. # +# Notes: Default means round-to-nearest mode, no floating-point # +# traps, and precision control = double extended. # +# # +# Step 1. Call slognd to obtain Y = log(X), the natural log of X. # +# Notes: Even if X is denormalized, log(X) is always normalized. # +# # +# Step 2. Compute log_10(X) = log(X) * (1/log(2)). # +# 2.1 Restore the user FPCR # +# 2.2 Return ans := Y * INV_L2. # +# # +# sLog2: # +# # +# Step 0. If X < 0, create a NaN and raise the invalid operation # +# flag. Otherwise, save FPCR in D1; set FpCR to default. # +# Notes: Default means round-to-nearest mode, no floating-point # +# traps, and precision control = double extended. # +# # +# Step 1. If X is not an integer power of two, i.e., X != 2^k, # +# go to Step 3. # +# # +# Step 2. Return k. # +# 2.1 Get integer k, X = 2^k. # +# 2.2 Restore the user FPCR. # +# 2.3 Return ans := convert-to-double-extended(k). # +# # +# Step 3. Call sLogN to obtain Y = log(X), the natural log of X. # +# # +# Step 4. Compute log_2(X) = log(X) * (1/log(2)). # +# 4.1 Restore the user FPCR # +# 4.2 Return ans := Y * INV_L2. # +# # +######################################################################### + +INV_L10: + long 0x3FFD0000,0xDE5BD8A9,0x37287195,0x00000000 + +INV_L2: + long 0x3FFF0000,0xB8AA3B29,0x5C17F0BC,0x00000000 + + global slog10 +#--entry point for Log10(X), X is normalized +slog10: + fmov.b &0x1,%fp0 + fcmp.x %fp0,(%a0) # if operand == 1, + fbeq.l ld_pzero # return an EXACT zero + + mov.l (%a0),%d1 + blt.w invalid + mov.l %d0,-(%sp) + clr.l %d0 + bsr slogn # log(X), X normal. + fmov.l (%sp)+,%fpcr + fmul.x INV_L10(%pc),%fp0 + bra t_inx2 + + global slog10d +#--entry point for Log10(X), X is denormalized +slog10d: + mov.l (%a0),%d1 + blt.w invalid + mov.l %d0,-(%sp) + clr.l %d0 + bsr slognd # log(X), X denorm. + fmov.l (%sp)+,%fpcr + fmul.x INV_L10(%pc),%fp0 + bra t_minx2 + + global slog2 +#--entry point for Log2(X), X is normalized +slog2: + mov.l (%a0),%d1 + blt.w invalid + + mov.l 8(%a0),%d1 + bne.b continue # X is not 2^k + + mov.l 4(%a0),%d1 + and.l &0x7FFFFFFF,%d1 + bne.b continue + +#--X = 2^k. + mov.w (%a0),%d1 + and.l &0x00007FFF,%d1 + sub.l &0x3FFF,%d1 + beq.l ld_pzero + fmov.l %d0,%fpcr + fmov.l %d1,%fp0 + bra t_inx2 + +continue: + mov.l %d0,-(%sp) + clr.l %d0 + bsr slogn # log(X), X normal. + fmov.l (%sp)+,%fpcr + fmul.x INV_L2(%pc),%fp0 + bra t_inx2 + +invalid: + bra t_operr + + global slog2d +#--entry point for Log2(X), X is denormalized +slog2d: + mov.l (%a0),%d1 + blt.w invalid + mov.l %d0,-(%sp) + clr.l %d0 + bsr slognd # log(X), X denorm. + fmov.l (%sp)+,%fpcr + fmul.x INV_L2(%pc),%fp0 + bra t_minx2 + +######################################################################### +# stwotox(): computes 2**X for a normalized input # +# stwotoxd(): computes 2**X for a denormalized input # +# stentox(): computes 10**X for a normalized input # +# stentoxd(): computes 10**X for a denormalized input # +# # +# INPUT *************************************************************** # +# a0 = pointer to extended precision input # +# d0 = round precision,mode # +# # +# OUTPUT ************************************************************** # +# fp0 = 2**X or 10**X # +# # +# ACCURACY and MONOTONICITY ******************************************* # +# The returned result is within 2 ulps in 64 significant bit, # +# i.e. within 0.5001 ulp to 53 bits if the result is subsequently # +# rounded to double precision. The result is provably monotonic # +# in double precision. # +# # +# ALGORITHM *********************************************************** # +# # +# twotox # +# 1. If |X| > 16480, go to ExpBig. # +# # +# 2. If |X| < 2**(-70), go to ExpSm. # +# # +# 3. Decompose X as X = N/64 + r where |r| <= 1/128. Furthermore # +# decompose N as # +# N = 64(M + M') + j, j = 0,1,2,...,63. # +# # +# 4. Overwrite r := r * log2. Then # +# 2**X = 2**(M') * 2**(M) * 2**(j/64) * exp(r). # +# Go to expr to compute that expression. # +# # +# tentox # +# 1. If |X| > 16480*log_10(2) (base 10 log of 2), go to ExpBig. # +# # +# 2. If |X| < 2**(-70), go to ExpSm. # +# # +# 3. Set y := X*log_2(10)*64 (base 2 log of 10). Set # +# N := round-to-int(y). Decompose N as # +# N = 64(M + M') + j, j = 0,1,2,...,63. # +# # +# 4. Define r as # +# r := ((X - N*L1)-N*L2) * L10 # +# where L1, L2 are the leading and trailing parts of # +# log_10(2)/64 and L10 is the natural log of 10. Then # +# 10**X = 2**(M') * 2**(M) * 2**(j/64) * exp(r). # +# Go to expr to compute that expression. # +# # +# expr # +# 1. Fetch 2**(j/64) from table as Fact1 and Fact2. # +# # +# 2. Overwrite Fact1 and Fact2 by # +# Fact1 := 2**(M) * Fact1 # +# Fact2 := 2**(M) * Fact2 # +# Thus Fact1 + Fact2 = 2**(M) * 2**(j/64). # +# # +# 3. Calculate P where 1 + P approximates exp(r): # +# P = r + r*r*(A1+r*(A2+...+r*A5)). # +# # +# 4. Let AdjFact := 2**(M'). Return # +# AdjFact * ( Fact1 + ((Fact1*P) + Fact2) ). # +# Exit. # +# # +# ExpBig # +# 1. Generate overflow by Huge * Huge if X > 0; otherwise, # +# generate underflow by Tiny * Tiny. # +# # +# ExpSm # +# 1. Return 1 + X. # +# # +######################################################################### + +L2TEN64: + long 0x406A934F,0x0979A371 # 64LOG10/LOG2 +L10TWO1: + long 0x3F734413,0x509F8000 # LOG2/64LOG10 + +L10TWO2: + long 0xBFCD0000,0xC0219DC1,0xDA994FD2,0x00000000 + +LOG10: long 0x40000000,0x935D8DDD,0xAAA8AC17,0x00000000 + +LOG2: long 0x3FFE0000,0xB17217F7,0xD1CF79AC,0x00000000 + +EXPA5: long 0x3F56C16D,0x6F7BD0B2 +EXPA4: long 0x3F811112,0x302C712C +EXPA3: long 0x3FA55555,0x55554CC1 +EXPA2: long 0x3FC55555,0x55554A54 +EXPA1: long 0x3FE00000,0x00000000,0x00000000,0x00000000 + +TEXPTBL: + long 0x3FFF0000,0x80000000,0x00000000,0x3F738000 + long 0x3FFF0000,0x8164D1F3,0xBC030773,0x3FBEF7CA + long 0x3FFF0000,0x82CD8698,0xAC2BA1D7,0x3FBDF8A9 + long 0x3FFF0000,0x843A28C3,0xACDE4046,0x3FBCD7C9 + long 0x3FFF0000,0x85AAC367,0xCC487B15,0xBFBDE8DA + long 0x3FFF0000,0x871F6196,0x9E8D1010,0x3FBDE85C + long 0x3FFF0000,0x88980E80,0x92DA8527,0x3FBEBBF1 + long 0x3FFF0000,0x8A14D575,0x496EFD9A,0x3FBB80CA + long 0x3FFF0000,0x8B95C1E3,0xEA8BD6E7,0xBFBA8373 + long 0x3FFF0000,0x8D1ADF5B,0x7E5BA9E6,0xBFBE9670 + long 0x3FFF0000,0x8EA4398B,0x45CD53C0,0x3FBDB700 + long 0x3FFF0000,0x9031DC43,0x1466B1DC,0x3FBEEEB0 + long 0x3FFF0000,0x91C3D373,0xAB11C336,0x3FBBFD6D + long 0x3FFF0000,0x935A2B2F,0x13E6E92C,0xBFBDB319 + long 0x3FFF0000,0x94F4EFA8,0xFEF70961,0x3FBDBA2B + long 0x3FFF0000,0x96942D37,0x20185A00,0x3FBE91D5 + long 0x3FFF0000,0x9837F051,0x8DB8A96F,0x3FBE8D5A + long 0x3FFF0000,0x99E04593,0x20B7FA65,0xBFBCDE7B + long 0x3FFF0000,0x9B8D39B9,0xD54E5539,0xBFBEBAAF + long 0x3FFF0000,0x9D3ED9A7,0x2CFFB751,0xBFBD86DA + long 0x3FFF0000,0x9EF53260,0x91A111AE,0xBFBEBEDD + long 0x3FFF0000,0xA0B0510F,0xB9714FC2,0x3FBCC96E + long 0x3FFF0000,0xA2704303,0x0C496819,0xBFBEC90B + long 0x3FFF0000,0xA43515AE,0x09E6809E,0x3FBBD1DB + long 0x3FFF0000,0xA5FED6A9,0xB15138EA,0x3FBCE5EB + long 0x3FFF0000,0xA7CD93B4,0xE965356A,0xBFBEC274 + long 0x3FFF0000,0xA9A15AB4,0xEA7C0EF8,0x3FBEA83C + long 0x3FFF0000,0xAB7A39B5,0xA93ED337,0x3FBECB00 + long 0x3FFF0000,0xAD583EEA,0x42A14AC6,0x3FBE9301 + long 0x3FFF0000,0xAF3B78AD,0x690A4375,0xBFBD8367 + long 0x3FFF0000,0xB123F581,0xD2AC2590,0xBFBEF05F + long 0x3FFF0000,0xB311C412,0xA9112489,0x3FBDFB3C + long 0x3FFF0000,0xB504F333,0xF9DE6484,0x3FBEB2FB + long 0x3FFF0000,0xB6FD91E3,0x28D17791,0x3FBAE2CB + long 0x3FFF0000,0xB8FBAF47,0x62FB9EE9,0x3FBCDC3C + long 0x3FFF0000,0xBAFF5AB2,0x133E45FB,0x3FBEE9AA + long 0x3FFF0000,0xBD08A39F,0x580C36BF,0xBFBEAEFD + long 0x3FFF0000,0xBF1799B6,0x7A731083,0xBFBCBF51 + long 0x3FFF0000,0xC12C4CCA,0x66709456,0x3FBEF88A + long 0x3FFF0000,0xC346CCDA,0x24976407,0x3FBD83B2 + long 0x3FFF0000,0xC5672A11,0x5506DADD,0x3FBDF8AB + long 0x3FFF0000,0xC78D74C8,0xABB9B15D,0xBFBDFB17 + long 0x3FFF0000,0xC9B9BD86,0x6E2F27A3,0xBFBEFE3C + long 0x3FFF0000,0xCBEC14FE,0xF2727C5D,0xBFBBB6F8 + long 0x3FFF0000,0xCE248C15,0x1F8480E4,0xBFBCEE53 + long 0x3FFF0000,0xD06333DA,0xEF2B2595,0xBFBDA4AE + long 0x3FFF0000,0xD2A81D91,0xF12AE45A,0x3FBC9124 + long 0x3FFF0000,0xD4F35AAB,0xCFEDFA1F,0x3FBEB243 + long 0x3FFF0000,0xD744FCCA,0xD69D6AF4,0x3FBDE69A + long 0x3FFF0000,0xD99D15C2,0x78AFD7B6,0xBFB8BC61 + long 0x3FFF0000,0xDBFBB797,0xDAF23755,0x3FBDF610 + long 0x3FFF0000,0xDE60F482,0x5E0E9124,0xBFBD8BE1 + long 0x3FFF0000,0xE0CCDEEC,0x2A94E111,0x3FBACB12 + long 0x3FFF0000,0xE33F8972,0xBE8A5A51,0x3FBB9BFE + long 0x3FFF0000,0xE5B906E7,0x7C8348A8,0x3FBCF2F4 + long 0x3FFF0000,0xE8396A50,0x3C4BDC68,0x3FBEF22F + long 0x3FFF0000,0xEAC0C6E7,0xDD24392F,0xBFBDBF4A + long 0x3FFF0000,0xED4F301E,0xD9942B84,0x3FBEC01A + long 0x3FFF0000,0xEFE4B99B,0xDCDAF5CB,0x3FBE8CAC + long 0x3FFF0000,0xF281773C,0x59FFB13A,0xBFBCBB3F + long 0x3FFF0000,0xF5257D15,0x2486CC2C,0x3FBEF73A + long 0x3FFF0000,0xF7D0DF73,0x0AD13BB9,0xBFB8B795 + long 0x3FFF0000,0xFA83B2DB,0x722A033A,0x3FBEF84B + long 0x3FFF0000,0xFD3E0C0C,0xF486C175,0xBFBEF581 + + set INT,L_SCR1 + + set X,FP_SCR0 + set XDCARE,X+2 + set XFRAC,X+4 + + set ADJFACT,FP_SCR0 + + set FACT1,FP_SCR0 + set FACT1HI,FACT1+4 + set FACT1LOW,FACT1+8 + + set FACT2,FP_SCR1 + set FACT2HI,FACT2+4 + set FACT2LOW,FACT2+8 + + global stwotox +#--ENTRY POINT FOR 2**(X), HERE X IS FINITE, NON-ZERO, AND NOT NAN'S +stwotox: + fmovm.x (%a0),&0x80 # LOAD INPUT + + mov.l (%a0),%d1 + mov.w 4(%a0),%d1 + fmov.x %fp0,X(%a6) + and.l &0x7FFFFFFF,%d1 + + cmp.l %d1,&0x3FB98000 # |X| >= 2**(-70)? + bge.b TWOOK1 + bra.w EXPBORS + +TWOOK1: + cmp.l %d1,&0x400D80C0 # |X| > 16480? + ble.b TWOMAIN + bra.w EXPBORS + +TWOMAIN: +#--USUAL CASE, 2^(-70) <= |X| <= 16480 + + fmov.x %fp0,%fp1 + fmul.s &0x42800000,%fp1 # 64 * X + fmov.l %fp1,INT(%a6) # N = ROUND-TO-INT(64 X) + mov.l %d2,-(%sp) + lea TEXPTBL(%pc),%a1 # LOAD ADDRESS OF TABLE OF 2^(J/64) + fmov.l INT(%a6),%fp1 # N --> FLOATING FMT + mov.l INT(%a6),%d1 + mov.l %d1,%d2 + and.l &0x3F,%d1 # D0 IS J + asl.l &4,%d1 # DISPLACEMENT FOR 2^(J/64) + add.l %d1,%a1 # ADDRESS FOR 2^(J/64) + asr.l &6,%d2 # d2 IS L, N = 64L + J + mov.l %d2,%d1 + asr.l &1,%d1 # D0 IS M + sub.l %d1,%d2 # d2 IS M', N = 64(M+M') + J + add.l &0x3FFF,%d2 + +#--SUMMARY: a1 IS ADDRESS FOR THE LEADING PORTION OF 2^(J/64), +#--D0 IS M WHERE N = 64(M+M') + J. NOTE THAT |M| <= 16140 BY DESIGN. +#--ADJFACT = 2^(M'). +#--REGISTERS SAVED SO FAR ARE (IN ORDER) FPCR, D0, FP1, a1, AND FP2. + + fmovm.x &0x0c,-(%sp) # save fp2/fp3 + + fmul.s &0x3C800000,%fp1 # (1/64)*N + mov.l (%a1)+,FACT1(%a6) + mov.l (%a1)+,FACT1HI(%a6) + mov.l (%a1)+,FACT1LOW(%a6) + mov.w (%a1)+,FACT2(%a6) + + fsub.x %fp1,%fp0 # X - (1/64)*INT(64 X) + + mov.w (%a1)+,FACT2HI(%a6) + clr.w FACT2HI+2(%a6) + clr.l FACT2LOW(%a6) + add.w %d1,FACT1(%a6) + fmul.x LOG2(%pc),%fp0 # FP0 IS R + add.w %d1,FACT2(%a6) + + bra.w expr + +EXPBORS: +#--FPCR, D0 SAVED + cmp.l %d1,&0x3FFF8000 + bgt.b TEXPBIG + +#--|X| IS SMALL, RETURN 1 + X + + fmov.l %d0,%fpcr # restore users round prec,mode + fadd.s &0x3F800000,%fp0 # RETURN 1 + X + bra t_pinx2 + +TEXPBIG: +#--|X| IS LARGE, GENERATE OVERFLOW IF X > 0; ELSE GENERATE UNDERFLOW +#--REGISTERS SAVE SO FAR ARE FPCR AND D0 + mov.l X(%a6),%d1 + cmp.l %d1,&0 + blt.b EXPNEG + + bra t_ovfl2 # t_ovfl expects positive value + +EXPNEG: + bra t_unfl2 # t_unfl expects positive value + + global stwotoxd +stwotoxd: +#--ENTRY POINT FOR 2**(X) FOR DENORMALIZED ARGUMENT + + fmov.l %d0,%fpcr # set user's rounding mode/precision + fmov.s &0x3F800000,%fp0 # RETURN 1 + X + mov.l (%a0),%d1 + or.l &0x00800001,%d1 + fadd.s %d1,%fp0 + bra t_pinx2 + + global stentox +#--ENTRY POINT FOR 10**(X), HERE X IS FINITE, NON-ZERO, AND NOT NAN'S +stentox: + fmovm.x (%a0),&0x80 # LOAD INPUT + + mov.l (%a0),%d1 + mov.w 4(%a0),%d1 + fmov.x %fp0,X(%a6) + and.l &0x7FFFFFFF,%d1 + + cmp.l %d1,&0x3FB98000 # |X| >= 2**(-70)? + bge.b TENOK1 + bra.w EXPBORS + +TENOK1: + cmp.l %d1,&0x400B9B07 # |X| <= 16480*log2/log10 ? + ble.b TENMAIN + bra.w EXPBORS + +TENMAIN: +#--USUAL CASE, 2^(-70) <= |X| <= 16480 LOG 2 / LOG 10 + + fmov.x %fp0,%fp1 + fmul.d L2TEN64(%pc),%fp1 # X*64*LOG10/LOG2 + fmov.l %fp1,INT(%a6) # N=INT(X*64*LOG10/LOG2) + mov.l %d2,-(%sp) + lea TEXPTBL(%pc),%a1 # LOAD ADDRESS OF TABLE OF 2^(J/64) + fmov.l INT(%a6),%fp1 # N --> FLOATING FMT + mov.l INT(%a6),%d1 + mov.l %d1,%d2 + and.l &0x3F,%d1 # D0 IS J + asl.l &4,%d1 # DISPLACEMENT FOR 2^(J/64) + add.l %d1,%a1 # ADDRESS FOR 2^(J/64) + asr.l &6,%d2 # d2 IS L, N = 64L + J + mov.l %d2,%d1 + asr.l &1,%d1 # D0 IS M + sub.l %d1,%d2 # d2 IS M', N = 64(M+M') + J + add.l &0x3FFF,%d2 + +#--SUMMARY: a1 IS ADDRESS FOR THE LEADING PORTION OF 2^(J/64), +#--D0 IS M WHERE N = 64(M+M') + J. NOTE THAT |M| <= 16140 BY DESIGN. +#--ADJFACT = 2^(M'). +#--REGISTERS SAVED SO FAR ARE (IN ORDER) FPCR, D0, FP1, a1, AND FP2. + fmovm.x &0x0c,-(%sp) # save fp2/fp3 + + fmov.x %fp1,%fp2 + + fmul.d L10TWO1(%pc),%fp1 # N*(LOG2/64LOG10)_LEAD + mov.l (%a1)+,FACT1(%a6) + + fmul.x L10TWO2(%pc),%fp2 # N*(LOG2/64LOG10)_TRAIL + + mov.l (%a1)+,FACT1HI(%a6) + mov.l (%a1)+,FACT1LOW(%a6) + fsub.x %fp1,%fp0 # X - N L_LEAD + mov.w (%a1)+,FACT2(%a6) + + fsub.x %fp2,%fp0 # X - N L_TRAIL + + mov.w (%a1)+,FACT2HI(%a6) + clr.w FACT2HI+2(%a6) + clr.l FACT2LOW(%a6) + + fmul.x LOG10(%pc),%fp0 # FP0 IS R + add.w %d1,FACT1(%a6) + add.w %d1,FACT2(%a6) + +expr: +#--FPCR, FP2, FP3 ARE SAVED IN ORDER AS SHOWN. +#--ADJFACT CONTAINS 2**(M'), FACT1 + FACT2 = 2**(M) * 2**(J/64). +#--FP0 IS R. THE FOLLOWING CODE COMPUTES +#-- 2**(M'+M) * 2**(J/64) * EXP(R) + + fmov.x %fp0,%fp1 + fmul.x %fp1,%fp1 # FP1 IS S = R*R + + fmov.d EXPA5(%pc),%fp2 # FP2 IS A5 + fmov.d EXPA4(%pc),%fp3 # FP3 IS A4 + + fmul.x %fp1,%fp2 # FP2 IS S*A5 + fmul.x %fp1,%fp3 # FP3 IS S*A4 + + fadd.d EXPA3(%pc),%fp2 # FP2 IS A3+S*A5 + fadd.d EXPA2(%pc),%fp3 # FP3 IS A2+S*A4 + + fmul.x %fp1,%fp2 # FP2 IS S*(A3+S*A5) + fmul.x %fp1,%fp3 # FP3 IS S*(A2+S*A4) + + fadd.d EXPA1(%pc),%fp2 # FP2 IS A1+S*(A3+S*A5) + fmul.x %fp0,%fp3 # FP3 IS R*S*(A2+S*A4) + + fmul.x %fp1,%fp2 # FP2 IS S*(A1+S*(A3+S*A5)) + fadd.x %fp3,%fp0 # FP0 IS R+R*S*(A2+S*A4) + fadd.x %fp2,%fp0 # FP0 IS EXP(R) - 1 + + fmovm.x (%sp)+,&0x30 # restore fp2/fp3 + +#--FINAL RECONSTRUCTION PROCESS +#--EXP(X) = 2^M*2^(J/64) + 2^M*2^(J/64)*(EXP(R)-1) - (1 OR 0) + + fmul.x FACT1(%a6),%fp0 + fadd.x FACT2(%a6),%fp0 + fadd.x FACT1(%a6),%fp0 + + fmov.l %d0,%fpcr # restore users round prec,mode + mov.w %d2,ADJFACT(%a6) # INSERT EXPONENT + mov.l (%sp)+,%d2 + mov.l &0x80000000,ADJFACT+4(%a6) + clr.l ADJFACT+8(%a6) + mov.b &FMUL_OP,%d1 # last inst is MUL + fmul.x ADJFACT(%a6),%fp0 # FINAL ADJUSTMENT + bra t_catch + + global stentoxd +stentoxd: +#--ENTRY POINT FOR 10**(X) FOR DENORMALIZED ARGUMENT + + fmov.l %d0,%fpcr # set user's rounding mode/precision + fmov.s &0x3F800000,%fp0 # RETURN 1 + X + mov.l (%a0),%d1 + or.l &0x00800001,%d1 + fadd.s %d1,%fp0 + bra t_pinx2 + +######################################################################### +# sscale(): computes the destination operand scaled by the source # +# operand. If the absoulute value of the source operand is # +# >= 2^14, an overflow or underflow is returned. # +# # +# INPUT *************************************************************** # +# a0 = pointer to double-extended source operand X # +# a1 = pointer to double-extended destination operand Y # +# # +# OUTPUT ************************************************************** # +# fp0 = scale(X,Y) # +# # +######################################################################### + +set SIGN, L_SCR1 + + global sscale +sscale: + mov.l %d0,-(%sp) # store off ctrl bits for now + + mov.w DST_EX(%a1),%d1 # get dst exponent + smi.b SIGN(%a6) # use SIGN to hold dst sign + andi.l &0x00007fff,%d1 # strip sign from dst exp + + mov.w SRC_EX(%a0),%d0 # check src bounds + andi.w &0x7fff,%d0 # clr src sign bit + cmpi.w %d0,&0x3fff # is src ~ ZERO? + blt.w src_small # yes + cmpi.w %d0,&0x400c # no; is src too big? + bgt.w src_out # yes + +# +# Source is within 2^14 range. +# +src_ok: + fintrz.x SRC(%a0),%fp0 # calc int of src + fmov.l %fp0,%d0 # int src to d0 +# don't want any accrued bits from the fintrz showing up later since +# we may need to read the fpsr for the last fp op in t_catch2(). + fmov.l &0x0,%fpsr + + tst.b DST_HI(%a1) # is dst denormalized? + bmi.b sok_norm + +# the dst is a DENORM. normalize the DENORM and add the adjustment to +# the src value. then, jump to the norm part of the routine. +sok_dnrm: + mov.l %d0,-(%sp) # save src for now + + mov.w DST_EX(%a1),FP_SCR0_EX(%a6) # make a copy + mov.l DST_HI(%a1),FP_SCR0_HI(%a6) + mov.l DST_LO(%a1),FP_SCR0_LO(%a6) + + lea FP_SCR0(%a6),%a0 # pass ptr to DENORM + bsr.l norm # normalize the DENORM + neg.l %d0 + add.l (%sp)+,%d0 # add adjustment to src + + fmovm.x FP_SCR0(%a6),&0x80 # load normalized DENORM + + cmpi.w %d0,&-0x3fff # is the shft amt really low? + bge.b sok_norm2 # thank goodness no + +# the multiply factor that we're trying to create should be a denorm +# for the multiply to work. therefore, we're going to actually do a +# multiply with a denorm which will cause an unimplemented data type +# exception to be put into the machine which will be caught and corrected +# later. we don't do this with the DENORMs above because this method +# is slower. but, don't fret, I don't see it being used much either. + fmov.l (%sp)+,%fpcr # restore user fpcr + mov.l &0x80000000,%d1 # load normalized mantissa + subi.l &-0x3fff,%d0 # how many should we shift? + neg.l %d0 # make it positive + cmpi.b %d0,&0x20 # is it > 32? + bge.b sok_dnrm_32 # yes + lsr.l %d0,%d1 # no; bit stays in upper lw + clr.l -(%sp) # insert zero low mantissa + mov.l %d1,-(%sp) # insert new high mantissa + clr.l -(%sp) # make zero exponent + bra.b sok_norm_cont +sok_dnrm_32: + subi.b &0x20,%d0 # get shift count + lsr.l %d0,%d1 # make low mantissa longword + mov.l %d1,-(%sp) # insert new low mantissa + clr.l -(%sp) # insert zero high mantissa + clr.l -(%sp) # make zero exponent + bra.b sok_norm_cont + +# the src will force the dst to a DENORM value or worse. so, let's +# create an fp multiply that will create the result. +sok_norm: + fmovm.x DST(%a1),&0x80 # load fp0 with normalized src +sok_norm2: + fmov.l (%sp)+,%fpcr # restore user fpcr + + addi.w &0x3fff,%d0 # turn src amt into exp value + swap %d0 # put exponent in high word + clr.l -(%sp) # insert new exponent + mov.l &0x80000000,-(%sp) # insert new high mantissa + mov.l %d0,-(%sp) # insert new lo mantissa + +sok_norm_cont: + fmov.l %fpcr,%d0 # d0 needs fpcr for t_catch2 + mov.b &FMUL_OP,%d1 # last inst is MUL + fmul.x (%sp)+,%fp0 # do the multiply + bra t_catch2 # catch any exceptions + +# +# Source is outside of 2^14 range. Test the sign and branch +# to the appropriate exception handler. +# +src_out: + mov.l (%sp)+,%d0 # restore ctrl bits + exg %a0,%a1 # swap src,dst ptrs + tst.b SRC_EX(%a1) # is src negative? + bmi t_unfl # yes; underflow + bra t_ovfl_sc # no; overflow + +# +# The source input is below 1, so we check for denormalized numbers +# and set unfl. +# +src_small: + tst.b DST_HI(%a1) # is dst denormalized? + bpl.b ssmall_done # yes + + mov.l (%sp)+,%d0 + fmov.l %d0,%fpcr # no; load control bits + mov.b &FMOV_OP,%d1 # last inst is MOVE + fmov.x DST(%a1),%fp0 # simply return dest + bra t_catch2 +ssmall_done: + mov.l (%sp)+,%d0 # load control bits into d1 + mov.l %a1,%a0 # pass ptr to dst + bra t_resdnrm + +######################################################################### +# smod(): computes the fp MOD of the input values X,Y. # +# srem(): computes the fp (IEEE) REM of the input values X,Y. # +# # +# INPUT *************************************************************** # +# a0 = pointer to extended precision input X # +# a1 = pointer to extended precision input Y # +# d0 = round precision,mode # +# # +# The input operands X and Y can be either normalized or # +# denormalized. # +# # +# OUTPUT ************************************************************** # +# fp0 = FREM(X,Y) or FMOD(X,Y) # +# # +# ALGORITHM *********************************************************** # +# # +# Step 1. Save and strip signs of X and Y: signX := sign(X), # +# signY := sign(Y), X := |X|, Y := |Y|, # +# signQ := signX EOR signY. Record whether MOD or REM # +# is requested. # +# # +# Step 2. Set L := expo(X)-expo(Y), k := 0, Q := 0. # +# If (L < 0) then # +# R := X, go to Step 4. # +# else # +# R := 2^(-L)X, j := L. # +# endif # +# # +# Step 3. Perform MOD(X,Y) # +# 3.1 If R = Y, go to Step 9. # +# 3.2 If R > Y, then { R := R - Y, Q := Q + 1} # +# 3.3 If j = 0, go to Step 4. # +# 3.4 k := k + 1, j := j - 1, Q := 2Q, R := 2R. Go to # +# Step 3.1. # +# # +# Step 4. At this point, R = X - QY = MOD(X,Y). Set # +# Last_Subtract := false (used in Step 7 below). If # +# MOD is requested, go to Step 6. # +# # +# Step 5. R = MOD(X,Y), but REM(X,Y) is requested. # +# 5.1 If R < Y/2, then R = MOD(X,Y) = REM(X,Y). Go to # +# Step 6. # +# 5.2 If R > Y/2, then { set Last_Subtract := true, # +# Q := Q + 1, Y := signY*Y }. Go to Step 6. # +# 5.3 This is the tricky case of R = Y/2. If Q is odd, # +# then { Q := Q + 1, signX := -signX }. # +# # +# Step 6. R := signX*R. # +# # +# Step 7. If Last_Subtract = true, R := R - Y. # +# # +# Step 8. Return signQ, last 7 bits of Q, and R as required. # +# # +# Step 9. At this point, R = 2^(-j)*X - Q Y = Y. Thus, # +# X = 2^(j)*(Q+1)Y. set Q := 2^(j)*(Q+1), # +# R := 0. Return signQ, last 7 bits of Q, and R. # +# # +######################################################################### + + set Mod_Flag,L_SCR3 + set Sc_Flag,L_SCR3+1 + + set SignY,L_SCR2 + set SignX,L_SCR2+2 + set SignQ,L_SCR3+2 + + set Y,FP_SCR0 + set Y_Hi,Y+4 + set Y_Lo,Y+8 + + set R,FP_SCR1 + set R_Hi,R+4 + set R_Lo,R+8 + +Scale: + long 0x00010000,0x80000000,0x00000000,0x00000000 + + global smod +smod: + clr.b FPSR_QBYTE(%a6) + mov.l %d0,-(%sp) # save ctrl bits + clr.b Mod_Flag(%a6) + bra.b Mod_Rem + + global srem +srem: + clr.b FPSR_QBYTE(%a6) + mov.l %d0,-(%sp) # save ctrl bits + mov.b &0x1,Mod_Flag(%a6) + +Mod_Rem: +#..Save sign of X and Y + movm.l &0x3f00,-(%sp) # save data registers + mov.w SRC_EX(%a0),%d3 + mov.w %d3,SignY(%a6) + and.l &0x00007FFF,%d3 # Y := |Y| + +# + mov.l SRC_HI(%a0),%d4 + mov.l SRC_LO(%a0),%d5 # (D3,D4,D5) is |Y| + + tst.l %d3 + bne.b Y_Normal + + mov.l &0x00003FFE,%d3 # $3FFD + 1 + tst.l %d4 + bne.b HiY_not0 + +HiY_0: + mov.l %d5,%d4 + clr.l %d5 + sub.l &32,%d3 + clr.l %d6 + bfffo %d4{&0:&32},%d6 + lsl.l %d6,%d4 + sub.l %d6,%d3 # (D3,D4,D5) is normalized +# ...with bias $7FFD + bra.b Chk_X + +HiY_not0: + clr.l %d6 + bfffo %d4{&0:&32},%d6 + sub.l %d6,%d3 + lsl.l %d6,%d4 + mov.l %d5,%d7 # a copy of D5 + lsl.l %d6,%d5 + neg.l %d6 + add.l &32,%d6 + lsr.l %d6,%d7 + or.l %d7,%d4 # (D3,D4,D5) normalized +# ...with bias $7FFD + bra.b Chk_X + +Y_Normal: + add.l &0x00003FFE,%d3 # (D3,D4,D5) normalized +# ...with bias $7FFD + +Chk_X: + mov.w DST_EX(%a1),%d0 + mov.w %d0,SignX(%a6) + mov.w SignY(%a6),%d1 + eor.l %d0,%d1 + and.l &0x00008000,%d1 + mov.w %d1,SignQ(%a6) # sign(Q) obtained + and.l &0x00007FFF,%d0 + mov.l DST_HI(%a1),%d1 + mov.l DST_LO(%a1),%d2 # (D0,D1,D2) is |X| + tst.l %d0 + bne.b X_Normal + mov.l &0x00003FFE,%d0 + tst.l %d1 + bne.b HiX_not0 + +HiX_0: + mov.l %d2,%d1 + clr.l %d2 + sub.l &32,%d0 + clr.l %d6 + bfffo %d1{&0:&32},%d6 + lsl.l %d6,%d1 + sub.l %d6,%d0 # (D0,D1,D2) is normalized +# ...with bias $7FFD + bra.b Init + +HiX_not0: + clr.l %d6 + bfffo %d1{&0:&32},%d6 + sub.l %d6,%d0 + lsl.l %d6,%d1 + mov.l %d2,%d7 # a copy of D2 + lsl.l %d6,%d2 + neg.l %d6 + add.l &32,%d6 + lsr.l %d6,%d7 + or.l %d7,%d1 # (D0,D1,D2) normalized +# ...with bias $7FFD + bra.b Init + +X_Normal: + add.l &0x00003FFE,%d0 # (D0,D1,D2) normalized +# ...with bias $7FFD + +Init: +# + mov.l %d3,L_SCR1(%a6) # save biased exp(Y) + mov.l %d0,-(%sp) # save biased exp(X) + sub.l %d3,%d0 # L := expo(X)-expo(Y) + + clr.l %d6 # D6 := carry <- 0 + clr.l %d3 # D3 is Q + mov.l &0,%a1 # A1 is k; j+k=L, Q=0 + +#..(Carry,D1,D2) is R + tst.l %d0 + bge.b Mod_Loop_pre + +#..expo(X) < expo(Y). Thus X = mod(X,Y) +# + mov.l (%sp)+,%d0 # restore d0 + bra.w Get_Mod + +Mod_Loop_pre: + addq.l &0x4,%sp # erase exp(X) +#..At this point R = 2^(-L)X; Q = 0; k = 0; and k+j = L +Mod_Loop: + tst.l %d6 # test carry bit + bgt.b R_GT_Y + +#..At this point carry = 0, R = (D1,D2), Y = (D4,D5) + cmp.l %d1,%d4 # compare hi(R) and hi(Y) + bne.b R_NE_Y + cmp.l %d2,%d5 # compare lo(R) and lo(Y) + bne.b R_NE_Y + +#..At this point, R = Y + bra.w Rem_is_0 + +R_NE_Y: +#..use the borrow of the previous compare + bcs.b R_LT_Y # borrow is set iff R < Y + +R_GT_Y: +#..If Carry is set, then Y < (Carry,D1,D2) < 2Y. Otherwise, Carry = 0 +#..and Y < (D1,D2) < 2Y. Either way, perform R - Y + sub.l %d5,%d2 # lo(R) - lo(Y) + subx.l %d4,%d1 # hi(R) - hi(Y) + clr.l %d6 # clear carry + addq.l &1,%d3 # Q := Q + 1 + +R_LT_Y: +#..At this point, Carry=0, R < Y. R = 2^(k-L)X - QY; k+j = L; j >= 0. + tst.l %d0 # see if j = 0. + beq.b PostLoop + + add.l %d3,%d3 # Q := 2Q + add.l %d2,%d2 # lo(R) = 2lo(R) + roxl.l &1,%d1 # hi(R) = 2hi(R) + carry + scs %d6 # set Carry if 2(R) overflows + addq.l &1,%a1 # k := k+1 + subq.l &1,%d0 # j := j - 1 +#..At this point, R=(Carry,D1,D2) = 2^(k-L)X - QY, j+k=L, j >= 0, R < 2Y. + + bra.b Mod_Loop + +PostLoop: +#..k = L, j = 0, Carry = 0, R = (D1,D2) = X - QY, R < Y. + +#..normalize R. + mov.l L_SCR1(%a6),%d0 # new biased expo of R + tst.l %d1 + bne.b HiR_not0 + +HiR_0: + mov.l %d2,%d1 + clr.l %d2 + sub.l &32,%d0 + clr.l %d6 + bfffo %d1{&0:&32},%d6 + lsl.l %d6,%d1 + sub.l %d6,%d0 # (D0,D1,D2) is normalized +# ...with bias $7FFD + bra.b Get_Mod + +HiR_not0: + clr.l %d6 + bfffo %d1{&0:&32},%d6 + bmi.b Get_Mod # already normalized + sub.l %d6,%d0 + lsl.l %d6,%d1 + mov.l %d2,%d7 # a copy of D2 + lsl.l %d6,%d2 + neg.l %d6 + add.l &32,%d6 + lsr.l %d6,%d7 + or.l %d7,%d1 # (D0,D1,D2) normalized + +# +Get_Mod: + cmp.l %d0,&0x000041FE + bge.b No_Scale +Do_Scale: + mov.w %d0,R(%a6) + mov.l %d1,R_Hi(%a6) + mov.l %d2,R_Lo(%a6) + mov.l L_SCR1(%a6),%d6 + mov.w %d6,Y(%a6) + mov.l %d4,Y_Hi(%a6) + mov.l %d5,Y_Lo(%a6) + fmov.x R(%a6),%fp0 # no exception + mov.b &1,Sc_Flag(%a6) + bra.b ModOrRem +No_Scale: + mov.l %d1,R_Hi(%a6) + mov.l %d2,R_Lo(%a6) + sub.l &0x3FFE,%d0 + mov.w %d0,R(%a6) + mov.l L_SCR1(%a6),%d6 + sub.l &0x3FFE,%d6 + mov.l %d6,L_SCR1(%a6) + fmov.x R(%a6),%fp0 + mov.w %d6,Y(%a6) + mov.l %d4,Y_Hi(%a6) + mov.l %d5,Y_Lo(%a6) + clr.b Sc_Flag(%a6) + +# +ModOrRem: + tst.b Mod_Flag(%a6) + beq.b Fix_Sign + + mov.l L_SCR1(%a6),%d6 # new biased expo(Y) + subq.l &1,%d6 # biased expo(Y/2) + cmp.l %d0,%d6 + blt.b Fix_Sign + bgt.b Last_Sub + + cmp.l %d1,%d4 + bne.b Not_EQ + cmp.l %d2,%d5 + bne.b Not_EQ + bra.w Tie_Case + +Not_EQ: + bcs.b Fix_Sign + +Last_Sub: +# + fsub.x Y(%a6),%fp0 # no exceptions + addq.l &1,%d3 # Q := Q + 1 + +# +Fix_Sign: +#..Get sign of X + mov.w SignX(%a6),%d6 + bge.b Get_Q + fneg.x %fp0 + +#..Get Q +# +Get_Q: + clr.l %d6 + mov.w SignQ(%a6),%d6 # D6 is sign(Q) + mov.l &8,%d7 + lsr.l %d7,%d6 + and.l &0x0000007F,%d3 # 7 bits of Q + or.l %d6,%d3 # sign and bits of Q +# swap %d3 +# fmov.l %fpsr,%d6 +# and.l &0xFF00FFFF,%d6 +# or.l %d3,%d6 +# fmov.l %d6,%fpsr # put Q in fpsr + mov.b %d3,FPSR_QBYTE(%a6) # put Q in fpsr + +# +Restore: + movm.l (%sp)+,&0xfc # {%d2-%d7} + mov.l (%sp)+,%d0 + fmov.l %d0,%fpcr + tst.b Sc_Flag(%a6) + beq.b Finish + mov.b &FMUL_OP,%d1 # last inst is MUL + fmul.x Scale(%pc),%fp0 # may cause underflow + bra t_catch2 +# the '040 package did this apparently to see if the dst operand for the +# preceding fmul was a denorm. but, it better not have been since the +# algorithm just got done playing with fp0 and expected no exceptions +# as a result. trust me... +# bra t_avoid_unsupp # check for denorm as a +# ;result of the scaling + +Finish: + mov.b &FMOV_OP,%d1 # last inst is MOVE + fmov.x %fp0,%fp0 # capture exceptions & round + bra t_catch2 + +Rem_is_0: +#..R = 2^(-j)X - Q Y = Y, thus R = 0 and quotient = 2^j (Q+1) + addq.l &1,%d3 + cmp.l %d0,&8 # D0 is j + bge.b Q_Big + + lsl.l %d0,%d3 + bra.b Set_R_0 + +Q_Big: + clr.l %d3 + +Set_R_0: + fmov.s &0x00000000,%fp0 + clr.b Sc_Flag(%a6) + bra.w Fix_Sign + +Tie_Case: +#..Check parity of Q + mov.l %d3,%d6 + and.l &0x00000001,%d6 + tst.l %d6 + beq.w Fix_Sign # Q is even + +#..Q is odd, Q := Q + 1, signX := -signX + addq.l &1,%d3 + mov.w SignX(%a6),%d6 + eor.l &0x00008000,%d6 + mov.w %d6,SignX(%a6) + bra.w Fix_Sign + +######################################################################### +# XDEF **************************************************************** # +# tag(): return the optype of the input ext fp number # +# # +# This routine is used by the 060FPLSP. # +# # +# XREF **************************************************************** # +# None # +# # +# INPUT *************************************************************** # +# a0 = pointer to extended precision operand # +# # +# OUTPUT ************************************************************** # +# d0 = value of type tag # +# one of: NORM, INF, QNAN, SNAN, DENORM, ZERO # +# # +# ALGORITHM *********************************************************** # +# Simply test the exponent, j-bit, and mantissa values to # +# determine the type of operand. # +# If it's an unnormalized zero, alter the operand and force it # +# to be a normal zero. # +# # +######################################################################### + + global tag +tag: + mov.w FTEMP_EX(%a0), %d0 # extract exponent + andi.w &0x7fff, %d0 # strip off sign + cmpi.w %d0, &0x7fff # is (EXP == MAX)? + beq.b inf_or_nan_x +not_inf_or_nan_x: + btst &0x7,FTEMP_HI(%a0) + beq.b not_norm_x +is_norm_x: + mov.b &NORM, %d0 + rts +not_norm_x: + tst.w %d0 # is exponent = 0? + bne.b is_unnorm_x +not_unnorm_x: + tst.l FTEMP_HI(%a0) + bne.b is_denorm_x + tst.l FTEMP_LO(%a0) + bne.b is_denorm_x +is_zero_x: + mov.b &ZERO, %d0 + rts +is_denorm_x: + mov.b &DENORM, %d0 + rts +is_unnorm_x: + bsr.l unnorm_fix # convert to norm,denorm,or zero + rts +is_unnorm_reg_x: + mov.b &UNNORM, %d0 + rts +inf_or_nan_x: + tst.l FTEMP_LO(%a0) + bne.b is_nan_x + mov.l FTEMP_HI(%a0), %d0 + and.l &0x7fffffff, %d0 # msb is a don't care! + bne.b is_nan_x +is_inf_x: + mov.b &INF, %d0 + rts +is_nan_x: + mov.b &QNAN, %d0 + rts + +############################################################# + +qnan: long 0x7fff0000, 0xffffffff, 0xffffffff + +######################################################################### +# XDEF **************************************************************** # +# t_dz(): Handle 060FPLSP dz exception for "flogn" emulation. # +# t_dz2(): Handle 060FPLSP dz exception for "fatanh" emulation. # +# # +# These rouitnes are used by the 060FPLSP package. # +# # +# XREF **************************************************************** # +# None # +# # +# INPUT *************************************************************** # +# a0 = pointer to extended precision source operand. # +# # +# OUTPUT ************************************************************** # +# fp0 = default DZ result. # +# # +# ALGORITHM *********************************************************** # +# Transcendental emulation for the 060FPLSP has detected that # +# a DZ exception should occur for the instruction. If DZ is disabled, # +# return the default result. # +# If DZ is enabled, the dst operand should be returned unscathed # +# in fp0 while fp1 is used to create a DZ exception so that the # +# operating system can log that such an event occurred. # +# # +######################################################################### + + global t_dz +t_dz: + tst.b SRC_EX(%a0) # check sign for neg or pos + bpl.b dz_pinf # branch if pos sign + + global t_dz2 +t_dz2: + ori.l &dzinf_mask+neg_mask,USER_FPSR(%a6) # set N/I/DZ/ADZ + + btst &dz_bit,FPCR_ENABLE(%a6) + bne.b dz_minf_ena + +# dz is disabled. return a -INF. + fmov.s &0xff800000,%fp0 # return -INF + rts + +# dz is enabled. create a dz exception so the user can record it +# but use fp1 instead. return the dst operand unscathed in fp0. +dz_minf_ena: + fmovm.x EXC_FP0(%a6),&0x80 # return fp0 unscathed + fmov.l USER_FPCR(%a6),%fpcr + fmov.s &0xbf800000,%fp1 # load -1 + fdiv.s &0x00000000,%fp1 # -1 / 0 + rts + +dz_pinf: + ori.l &dzinf_mask,USER_FPSR(%a6) # set I/DZ/ADZ + + btst &dz_bit,FPCR_ENABLE(%a6) + bne.b dz_pinf_ena + +# dz is disabled. return a +INF. + fmov.s &0x7f800000,%fp0 # return +INF + rts + +# dz is enabled. create a dz exception so the user can record it +# but use fp1 instead. return the dst operand unscathed in fp0. +dz_pinf_ena: + fmovm.x EXC_FP0(%a6),&0x80 # return fp0 unscathed + fmov.l USER_FPCR(%a6),%fpcr + fmov.s &0x3f800000,%fp1 # load +1 + fdiv.s &0x00000000,%fp1 # +1 / 0 + rts + +######################################################################### +# XDEF **************************************************************** # +# t_operr(): Handle 060FPLSP OPERR exception during emulation. # +# # +# This routine is used by the 060FPLSP package. # +# # +# XREF **************************************************************** # +# None. # +# # +# INPUT *************************************************************** # +# fp1 = source operand # +# # +# OUTPUT ************************************************************** # +# fp0 = default result # +# fp1 = unchanged # +# # +# ALGORITHM *********************************************************** # +# An operand error should occur as the result of transcendental # +# emulation in the 060FPLSP. If OPERR is disabled, just return a NAN # +# in fp0. If OPERR is enabled, return the dst operand unscathed in fp0 # +# and the source operand in fp1. Use fp2 to create an OPERR exception # +# so that the operating system can log the event. # +# # +######################################################################### + + global t_operr +t_operr: + ori.l &opnan_mask,USER_FPSR(%a6) # set NAN/OPERR/AIOP + + btst &operr_bit,FPCR_ENABLE(%a6) + bne.b operr_ena + +# operr is disabled. return a QNAN in fp0 + fmovm.x qnan(%pc),&0x80 # return QNAN + rts + +# operr is enabled. create an operr exception so the user can record it +# but use fp2 instead. return the dst operand unscathed in fp0. +operr_ena: + fmovm.x EXC_FP0(%a6),&0x80 # return fp0 unscathed + fmov.l USER_FPCR(%a6),%fpcr + fmovm.x &0x04,-(%sp) # save fp2 + fmov.s &0x7f800000,%fp2 # load +INF + fmul.s &0x00000000,%fp2 # +INF x 0 + fmovm.x (%sp)+,&0x20 # restore fp2 + rts + +pls_huge: + long 0x7ffe0000,0xffffffff,0xffffffff +mns_huge: + long 0xfffe0000,0xffffffff,0xffffffff +pls_tiny: + long 0x00000000,0x80000000,0x00000000 +mns_tiny: + long 0x80000000,0x80000000,0x00000000 + +######################################################################### +# XDEF **************************************************************** # +# t_unfl(): Handle 060FPLSP underflow exception during emulation. # +# t_unfl2(): Handle 060FPLSP underflow exception during # +# emulation. result always positive. # +# # +# This routine is used by the 060FPLSP package. # +# # +# XREF **************************************************************** # +# None. # +# # +# INPUT *************************************************************** # +# a0 = pointer to extended precision source operand # +# # +# OUTPUT ************************************************************** # +# fp0 = default underflow result # +# # +# ALGORITHM *********************************************************** # +# An underflow should occur as the result of transcendental # +# emulation in the 060FPLSP. Create an underflow by using "fmul" # +# and two very small numbers of appropriate sign so the the operating # +# system can log the event. # +# # +######################################################################### + + global t_unfl +t_unfl: + tst.b SRC_EX(%a0) + bpl.b unf_pos + + global t_unfl2 +t_unfl2: + ori.l &unfinx_mask+neg_mask,USER_FPSR(%a6) # set N/UNFL/INEX2/AUNFL/AINEX + + fmov.l USER_FPCR(%a6),%fpcr + fmovm.x mns_tiny(%pc),&0x80 + fmul.x pls_tiny(%pc),%fp0 + + fmov.l %fpsr,%d0 + rol.l &0x8,%d0 + mov.b %d0,FPSR_CC(%a6) + rts +unf_pos: + ori.w &unfinx_mask,FPSR_EXCEPT(%a6) # set UNFL/INEX2/AUNFL/AINEX + + fmov.l USER_FPCR(%a6),%fpcr + fmovm.x pls_tiny(%pc),&0x80 + fmul.x %fp0,%fp0 + + fmov.l %fpsr,%d0 + rol.l &0x8,%d0 + mov.b %d0,FPSR_CC(%a6) + rts + +######################################################################### +# XDEF **************************************************************** # +# t_ovfl(): Handle 060FPLSP overflow exception during emulation. # +# (monadic) # +# t_ovfl2(): Handle 060FPLSP overflow exception during # +# emulation. result always positive. (dyadic) # +# t_ovfl_sc(): Handle 060FPLSP overflow exception during # +# emulation for "fscale". # +# # +# This routine is used by the 060FPLSP package. # +# # +# XREF **************************************************************** # +# None. # +# # +# INPUT *************************************************************** # +# a0 = pointer to extended precision source operand # +# # +# OUTPUT ************************************************************** # +# fp0 = default underflow result # +# # +# ALGORITHM *********************************************************** # +# An overflow should occur as the result of transcendental # +# emulation in the 060FPLSP. Create an overflow by using "fmul" # +# and two very lareg numbers of appropriate sign so the the operating # +# system can log the event. # +# For t_ovfl_sc() we take special care not to lose the INEX2 bit. # +# # +######################################################################### + + global t_ovfl_sc +t_ovfl_sc: + ori.l &ovfl_inx_mask,USER_FPSR(%a6) # set OVFL/AOVFL/AINEX + + mov.b %d0,%d1 # fetch rnd prec,mode + andi.b &0xc0,%d1 # extract prec + beq.w ovfl_work + +# dst op is a DENORM. we have to normalize the mantissa to see if the +# result would be inexact for the given precision. make a copy of the +# dst so we don't screw up the version passed to us. + mov.w LOCAL_EX(%a0),FP_SCR0_EX(%a6) + mov.l LOCAL_HI(%a0),FP_SCR0_HI(%a6) + mov.l LOCAL_LO(%a0),FP_SCR0_LO(%a6) + lea FP_SCR0(%a6),%a0 # pass ptr to FP_SCR0 + movm.l &0xc080,-(%sp) # save d0-d1/a0 + bsr.l norm # normalize mantissa + movm.l (%sp)+,&0x0103 # restore d0-d1/a0 + + cmpi.b %d1,&0x40 # is precision sgl? + bne.b ovfl_sc_dbl # no; dbl +ovfl_sc_sgl: + tst.l LOCAL_LO(%a0) # is lo lw of sgl set? + bne.b ovfl_sc_inx # yes + tst.b 3+LOCAL_HI(%a0) # is lo byte of hi lw set? + bne.b ovfl_sc_inx # yes + bra.w ovfl_work # don't set INEX2 +ovfl_sc_dbl: + mov.l LOCAL_LO(%a0),%d1 # are any of lo 11 bits of + andi.l &0x7ff,%d1 # dbl mantissa set? + beq.w ovfl_work # no; don't set INEX2 +ovfl_sc_inx: + ori.l &inex2_mask,USER_FPSR(%a6) # set INEX2 + bra.b ovfl_work # continue + + global t_ovfl +t_ovfl: + ori.w &ovfinx_mask,FPSR_EXCEPT(%a6) # set OVFL/INEX2/AOVFL/AINEX +ovfl_work: + tst.b SRC_EX(%a0) + bpl.b ovfl_p +ovfl_m: + fmov.l USER_FPCR(%a6),%fpcr + fmovm.x mns_huge(%pc),&0x80 + fmul.x pls_huge(%pc),%fp0 + + fmov.l %fpsr,%d0 + rol.l &0x8,%d0 + ori.b &neg_mask,%d0 + mov.b %d0,FPSR_CC(%a6) + rts +ovfl_p: + fmov.l USER_FPCR(%a6),%fpcr + fmovm.x pls_huge(%pc),&0x80 + fmul.x pls_huge(%pc),%fp0 + + fmov.l %fpsr,%d0 + rol.l &0x8,%d0 + mov.b %d0,FPSR_CC(%a6) + rts + + global t_ovfl2 +t_ovfl2: + ori.w &ovfinx_mask,FPSR_EXCEPT(%a6) # set OVFL/INEX2/AOVFL/AINEX + fmov.l USER_FPCR(%a6),%fpcr + fmovm.x pls_huge(%pc),&0x80 + fmul.x pls_huge(%pc),%fp0 + + fmov.l %fpsr,%d0 + rol.l &0x8,%d0 + mov.b %d0,FPSR_CC(%a6) + rts + +######################################################################### +# XDEF **************************************************************** # +# t_catch(): Handle 060FPLSP OVFL,UNFL,or INEX2 exception during # +# emulation. # +# t_catch2(): Handle 060FPLSP OVFL,UNFL,or INEX2 exception during # +# emulation. # +# # +# These routines are used by the 060FPLSP package. # +# # +# XREF **************************************************************** # +# None. # +# # +# INPUT *************************************************************** # +# fp0 = default underflow or overflow result # +# # +# OUTPUT ************************************************************** # +# fp0 = default result # +# # +# ALGORITHM *********************************************************** # +# If an overflow or underflow occurred during the last # +# instruction of transcendental 060FPLSP emulation, then it has already # +# occurred and has been logged. Now we need to see if an inexact # +# exception should occur. # +# # +######################################################################### + + global t_catch2 +t_catch2: + fmov.l %fpsr,%d0 + or.l %d0,USER_FPSR(%a6) + bra.b inx2_work + + global t_catch +t_catch: + fmov.l %fpsr,%d0 + or.l %d0,USER_FPSR(%a6) + +######################################################################### +# XDEF **************************************************************** # +# t_inx2(): Handle inexact 060FPLSP exception during emulation. # +# t_pinx2(): Handle inexact 060FPLSP exception for "+" results. # +# t_minx2(): Handle inexact 060FPLSP exception for "-" results. # +# # +# XREF **************************************************************** # +# None. # +# # +# INPUT *************************************************************** # +# fp0 = default result # +# # +# OUTPUT ************************************************************** # +# fp0 = default result # +# # +# ALGORITHM *********************************************************** # +# The last instruction of transcendental emulation for the # +# 060FPLSP should be inexact. So, if inexact is enabled, then we create # +# the event here by adding a large and very small number together # +# so that the operating system can log the event. # +# Must check, too, if the result was zero, in which case we just # +# set the FPSR bits and return. # +# # +######################################################################### + + global t_inx2 +t_inx2: + fblt.w t_minx2 + fbeq.w inx2_zero + + global t_pinx2 +t_pinx2: + ori.w &inx2a_mask,FPSR_EXCEPT(%a6) # set INEX2/AINEX + bra.b inx2_work + + global t_minx2 +t_minx2: + ori.l &inx2a_mask+neg_mask,USER_FPSR(%a6) + +inx2_work: + btst &inex2_bit,FPCR_ENABLE(%a6) # is inexact enabled? + bne.b inx2_work_ena # yes + rts +inx2_work_ena: + fmov.l USER_FPCR(%a6),%fpcr # insert user's exceptions + fmov.s &0x3f800000,%fp1 # load +1 + fadd.x pls_tiny(%pc),%fp1 # cause exception + rts + +inx2_zero: + mov.b &z_bmask,FPSR_CC(%a6) + ori.w &inx2a_mask,2+USER_FPSR(%a6) # set INEX/AINEX + rts + +######################################################################### +# XDEF **************************************************************** # +# t_extdnrm(): Handle DENORM inputs in 060FPLSP. # +# t_resdnrm(): Handle DENORM inputs in 060FPLSP for "fscale". # +# # +# This routine is used by the 060FPLSP package. # +# # +# XREF **************************************************************** # +# None. # +# # +# INPUT *************************************************************** # +# a0 = pointer to extended precision input operand # +# # +# OUTPUT ************************************************************** # +# fp0 = default result # +# # +# ALGORITHM *********************************************************** # +# For all functions that have a denormalized input and that # +# f(x)=x, this is the entry point. # +# DENORM value is moved using "fmove" which triggers an exception # +# if enabled so the operating system can log the event. # +# # +######################################################################### + + global t_extdnrm +t_extdnrm: + fmov.l USER_FPCR(%a6),%fpcr + fmov.x SRC_EX(%a0),%fp0 + fmov.l %fpsr,%d0 + ori.l &unfinx_mask,%d0 + or.l %d0,USER_FPSR(%a6) + rts + + global t_resdnrm +t_resdnrm: + fmov.l USER_FPCR(%a6),%fpcr + fmov.x SRC_EX(%a0),%fp0 + fmov.l %fpsr,%d0 + or.l %d0,USER_FPSR(%a6) + rts + +########################################## + +# +# sto_cos: +# This is used by fsincos library emulation. The correct +# values are already in fp0 and fp1 so we do nothing here. +# + global sto_cos +sto_cos: + rts + +########################################## + +# +# dst_qnan --- force result when destination is a NaN +# + global dst_qnan +dst_qnan: + fmov.x DST(%a1),%fp0 + tst.b DST_EX(%a1) + bmi.b dst_qnan_m +dst_qnan_p: + mov.b &nan_bmask,FPSR_CC(%a6) + rts +dst_qnan_m: + mov.b &nan_bmask+neg_bmask,FPSR_CC(%a6) + rts + +# +# src_qnan --- force result when source is a NaN +# + global src_qnan +src_qnan: + fmov.x SRC(%a0),%fp0 + tst.b SRC_EX(%a0) + bmi.b src_qnan_m +src_qnan_p: + mov.b &nan_bmask,FPSR_CC(%a6) + rts +src_qnan_m: + mov.b &nan_bmask+neg_bmask,FPSR_CC(%a6) + rts + +########################################## + +# +# Native instruction support +# +# Some systems may need entry points even for 68060 native +# instructions. These routines are provided for +# convenience. +# + global _fadds_ +_fadds_: + fmov.l %fpcr,-(%sp) # save fpcr + fmov.l &0x00000000,%fpcr # clear fpcr for load + fmov.s 0x8(%sp),%fp0 # load sgl dst + fmov.l (%sp)+,%fpcr # restore fpcr + fadd.s 0x8(%sp),%fp0 # fadd w/ sgl src + rts + + global _faddd_ +_faddd_: + fmov.l %fpcr,-(%sp) # save fpcr + fmov.l &0x00000000,%fpcr # clear fpcr for load + fmov.d 0x8(%sp),%fp0 # load dbl dst + fmov.l (%sp)+,%fpcr # restore fpcr + fadd.d 0xc(%sp),%fp0 # fadd w/ dbl src + rts + + global _faddx_ +_faddx_: + fmovm.x 0x4(%sp),&0x80 # load ext dst + fadd.x 0x10(%sp),%fp0 # fadd w/ ext src + rts + + global _fsubs_ +_fsubs_: + fmov.l %fpcr,-(%sp) # save fpcr + fmov.l &0x00000000,%fpcr # clear fpcr for load + fmov.s 0x8(%sp),%fp0 # load sgl dst + fmov.l (%sp)+,%fpcr # restore fpcr + fsub.s 0x8(%sp),%fp0 # fsub w/ sgl src + rts + + global _fsubd_ +_fsubd_: + fmov.l %fpcr,-(%sp) # save fpcr + fmov.l &0x00000000,%fpcr # clear fpcr for load + fmov.d 0x8(%sp),%fp0 # load dbl dst + fmov.l (%sp)+,%fpcr # restore fpcr + fsub.d 0xc(%sp),%fp0 # fsub w/ dbl src + rts + + global _fsubx_ +_fsubx_: + fmovm.x 0x4(%sp),&0x80 # load ext dst + fsub.x 0x10(%sp),%fp0 # fsub w/ ext src + rts + + global _fmuls_ +_fmuls_: + fmov.l %fpcr,-(%sp) # save fpcr + fmov.l &0x00000000,%fpcr # clear fpcr for load + fmov.s 0x8(%sp),%fp0 # load sgl dst + fmov.l (%sp)+,%fpcr # restore fpcr + fmul.s 0x8(%sp),%fp0 # fmul w/ sgl src + rts + + global _fmuld_ +_fmuld_: + fmov.l %fpcr,-(%sp) # save fpcr + fmov.l &0x00000000,%fpcr # clear fpcr for load + fmov.d 0x8(%sp),%fp0 # load dbl dst + fmov.l (%sp)+,%fpcr # restore fpcr + fmul.d 0xc(%sp),%fp0 # fmul w/ dbl src + rts + + global _fmulx_ +_fmulx_: + fmovm.x 0x4(%sp),&0x80 # load ext dst + fmul.x 0x10(%sp),%fp0 # fmul w/ ext src + rts + + global _fdivs_ +_fdivs_: + fmov.l %fpcr,-(%sp) # save fpcr + fmov.l &0x00000000,%fpcr # clear fpcr for load + fmov.s 0x8(%sp),%fp0 # load sgl dst + fmov.l (%sp)+,%fpcr # restore fpcr + fdiv.s 0x8(%sp),%fp0 # fdiv w/ sgl src + rts + + global _fdivd_ +_fdivd_: + fmov.l %fpcr,-(%sp) # save fpcr + fmov.l &0x00000000,%fpcr # clear fpcr for load + fmov.d 0x8(%sp),%fp0 # load dbl dst + fmov.l (%sp)+,%fpcr # restore fpcr + fdiv.d 0xc(%sp),%fp0 # fdiv w/ dbl src + rts + + global _fdivx_ +_fdivx_: + fmovm.x 0x4(%sp),&0x80 # load ext dst + fdiv.x 0x10(%sp),%fp0 # fdiv w/ ext src + rts + + global _fabss_ +_fabss_: + fabs.s 0x4(%sp),%fp0 # fabs w/ sgl src + rts + + global _fabsd_ +_fabsd_: + fabs.d 0x4(%sp),%fp0 # fabs w/ dbl src + rts + + global _fabsx_ +_fabsx_: + fabs.x 0x4(%sp),%fp0 # fabs w/ ext src + rts + + global _fnegs_ +_fnegs_: + fneg.s 0x4(%sp),%fp0 # fneg w/ sgl src + rts + + global _fnegd_ +_fnegd_: + fneg.d 0x4(%sp),%fp0 # fneg w/ dbl src + rts + + global _fnegx_ +_fnegx_: + fneg.x 0x4(%sp),%fp0 # fneg w/ ext src + rts + + global _fsqrts_ +_fsqrts_: + fsqrt.s 0x4(%sp),%fp0 # fsqrt w/ sgl src + rts + + global _fsqrtd_ +_fsqrtd_: + fsqrt.d 0x4(%sp),%fp0 # fsqrt w/ dbl src + rts + + global _fsqrtx_ +_fsqrtx_: + fsqrt.x 0x4(%sp),%fp0 # fsqrt w/ ext src + rts + + global _fints_ +_fints_: + fint.s 0x4(%sp),%fp0 # fint w/ sgl src + rts + + global _fintd_ +_fintd_: + fint.d 0x4(%sp),%fp0 # fint w/ dbl src + rts + + global _fintx_ +_fintx_: + fint.x 0x4(%sp),%fp0 # fint w/ ext src + rts + + global _fintrzs_ +_fintrzs_: + fintrz.s 0x4(%sp),%fp0 # fintrz w/ sgl src + rts + + global _fintrzd_ +_fintrzd_: + fintrz.d 0x4(%sp),%fp0 # fintrx w/ dbl src + rts + + global _fintrzx_ +_fintrzx_: + fintrz.x 0x4(%sp),%fp0 # fintrz w/ ext src + rts + +######################################################################## + +######################################################################### +# src_zero(): Return signed zero according to sign of src operand. # +######################################################################### + global src_zero +src_zero: + tst.b SRC_EX(%a0) # get sign of src operand + bmi.b ld_mzero # if neg, load neg zero + +# +# ld_pzero(): return a positive zero. +# + global ld_pzero +ld_pzero: + fmov.s &0x00000000,%fp0 # load +0 + mov.b &z_bmask,FPSR_CC(%a6) # set 'Z' ccode bit + rts + +# ld_mzero(): return a negative zero. + global ld_mzero +ld_mzero: + fmov.s &0x80000000,%fp0 # load -0 + mov.b &neg_bmask+z_bmask,FPSR_CC(%a6) # set 'N','Z' ccode bits + rts + +######################################################################### +# dst_zero(): Return signed zero according to sign of dst operand. # +######################################################################### + global dst_zero +dst_zero: + tst.b DST_EX(%a1) # get sign of dst operand + bmi.b ld_mzero # if neg, load neg zero + bra.b ld_pzero # load positive zero + +######################################################################### +# src_inf(): Return signed inf according to sign of src operand. # +######################################################################### + global src_inf +src_inf: + tst.b SRC_EX(%a0) # get sign of src operand + bmi.b ld_minf # if negative branch + +# +# ld_pinf(): return a positive infinity. +# + global ld_pinf +ld_pinf: + fmov.s &0x7f800000,%fp0 # load +INF + mov.b &inf_bmask,FPSR_CC(%a6) # set 'INF' ccode bit + rts + +# +# ld_minf():return a negative infinity. +# + global ld_minf +ld_minf: + fmov.s &0xff800000,%fp0 # load -INF + mov.b &neg_bmask+inf_bmask,FPSR_CC(%a6) # set 'N','I' ccode bits + rts + +######################################################################### +# dst_inf(): Return signed inf according to sign of dst operand. # +######################################################################### + global dst_inf +dst_inf: + tst.b DST_EX(%a1) # get sign of dst operand + bmi.b ld_minf # if negative branch + bra.b ld_pinf + + global szr_inf +################################################################# +# szr_inf(): Return +ZERO for a negative src operand or # +# +INF for a positive src operand. # +# Routine used for fetox, ftwotox, and ftentox. # +################################################################# +szr_inf: + tst.b SRC_EX(%a0) # check sign of source + bmi.b ld_pzero + bra.b ld_pinf + +######################################################################### +# sopr_inf(): Return +INF for a positive src operand or # +# jump to operand error routine for a negative src operand. # +# Routine used for flogn, flognp1, flog10, and flog2. # +######################################################################### + global sopr_inf +sopr_inf: + tst.b SRC_EX(%a0) # check sign of source + bmi.w t_operr + bra.b ld_pinf + +################################################################# +# setoxm1i(): Return minus one for a negative src operand or # +# positive infinity for a positive src operand. # +# Routine used for fetoxm1. # +################################################################# + global setoxm1i +setoxm1i: + tst.b SRC_EX(%a0) # check sign of source + bmi.b ld_mone + bra.b ld_pinf + +######################################################################### +# src_one(): Return signed one according to sign of src operand. # +######################################################################### + global src_one +src_one: + tst.b SRC_EX(%a0) # check sign of source + bmi.b ld_mone + +# +# ld_pone(): return positive one. +# + global ld_pone +ld_pone: + fmov.s &0x3f800000,%fp0 # load +1 + clr.b FPSR_CC(%a6) + rts + +# +# ld_mone(): return negative one. +# + global ld_mone +ld_mone: + fmov.s &0xbf800000,%fp0 # load -1 + mov.b &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit + rts + +ppiby2: long 0x3fff0000, 0xc90fdaa2, 0x2168c235 +mpiby2: long 0xbfff0000, 0xc90fdaa2, 0x2168c235 + +################################################################# +# spi_2(): Return signed PI/2 according to sign of src operand. # +################################################################# + global spi_2 +spi_2: + tst.b SRC_EX(%a0) # check sign of source + bmi.b ld_mpi2 + +# +# ld_ppi2(): return positive PI/2. +# + global ld_ppi2 +ld_ppi2: + fmov.l %d0,%fpcr + fmov.x ppiby2(%pc),%fp0 # load +pi/2 + bra.w t_pinx2 # set INEX2 + +# +# ld_mpi2(): return negative PI/2. +# + global ld_mpi2 +ld_mpi2: + fmov.l %d0,%fpcr + fmov.x mpiby2(%pc),%fp0 # load -pi/2 + bra.w t_minx2 # set INEX2 + +#################################################### +# The following routines give support for fsincos. # +#################################################### + +# +# ssincosz(): When the src operand is ZERO, store a one in the +# cosine register and return a ZERO in fp0 w/ the same sign +# as the src operand. +# + global ssincosz +ssincosz: + fmov.s &0x3f800000,%fp1 + tst.b SRC_EX(%a0) # test sign + bpl.b sincoszp + fmov.s &0x80000000,%fp0 # return sin result in fp0 + mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) + rts +sincoszp: + fmov.s &0x00000000,%fp0 # return sin result in fp0 + mov.b &z_bmask,FPSR_CC(%a6) + rts + +# +# ssincosi(): When the src operand is INF, store a QNAN in the cosine +# register and jump to the operand error routine for negative +# src operands. +# + global ssincosi +ssincosi: + fmov.x qnan(%pc),%fp1 # load NAN + bra.w t_operr + +# +# ssincosqnan(): When the src operand is a QNAN, store the QNAN in the cosine +# register and branch to the src QNAN routine. +# + global ssincosqnan +ssincosqnan: + fmov.x LOCAL_EX(%a0),%fp1 + bra.w src_qnan + +######################################################################## + + global smod_sdnrm + global smod_snorm +smod_sdnrm: +smod_snorm: + mov.b DTAG(%a6),%d1 + beq.l smod + cmpi.b %d1,&ZERO + beq.w smod_zro + cmpi.b %d1,&INF + beq.l t_operr + cmpi.b %d1,&DENORM + beq.l smod + bra.l dst_qnan + + global smod_szero +smod_szero: + mov.b DTAG(%a6),%d1 + beq.l t_operr + cmpi.b %d1,&ZERO + beq.l t_operr + cmpi.b %d1,&INF + beq.l t_operr + cmpi.b %d1,&DENORM + beq.l t_operr + bra.l dst_qnan + + global smod_sinf +smod_sinf: + mov.b DTAG(%a6),%d1 + beq.l smod_fpn + cmpi.b %d1,&ZERO + beq.l smod_zro + cmpi.b %d1,&INF + beq.l t_operr + cmpi.b %d1,&DENORM + beq.l smod_fpn + bra.l dst_qnan + +smod_zro: +srem_zro: + mov.b SRC_EX(%a0),%d1 # get src sign + mov.b DST_EX(%a1),%d0 # get dst sign + eor.b %d0,%d1 # get qbyte sign + andi.b &0x80,%d1 + mov.b %d1,FPSR_QBYTE(%a6) + tst.b %d0 + bpl.w ld_pzero + bra.w ld_mzero + +smod_fpn: +srem_fpn: + clr.b FPSR_QBYTE(%a6) + mov.l %d0,-(%sp) + mov.b SRC_EX(%a0),%d1 # get src sign + mov.b DST_EX(%a1),%d0 # get dst sign + eor.b %d0,%d1 # get qbyte sign + andi.b &0x80,%d1 + mov.b %d1,FPSR_QBYTE(%a6) + cmpi.b DTAG(%a6),&DENORM + bne.b smod_nrm + lea DST(%a1),%a0 + mov.l (%sp)+,%d0 + bra t_resdnrm +smod_nrm: + fmov.l (%sp)+,%fpcr + fmov.x DST(%a1),%fp0 + tst.b DST_EX(%a1) + bmi.b smod_nrm_neg + rts + +smod_nrm_neg: + mov.b &neg_bmask,FPSR_CC(%a6) # set 'N' code + rts + +######################################################################### + global srem_snorm + global srem_sdnrm +srem_sdnrm: +srem_snorm: + mov.b DTAG(%a6),%d1 + beq.l srem + cmpi.b %d1,&ZERO + beq.w srem_zro + cmpi.b %d1,&INF + beq.l t_operr + cmpi.b %d1,&DENORM + beq.l srem + bra.l dst_qnan + + global srem_szero +srem_szero: + mov.b DTAG(%a6),%d1 + beq.l t_operr + cmpi.b %d1,&ZERO + beq.l t_operr + cmpi.b %d1,&INF + beq.l t_operr + cmpi.b %d1,&DENORM + beq.l t_operr + bra.l dst_qnan + + global srem_sinf +srem_sinf: + mov.b DTAG(%a6),%d1 + beq.w srem_fpn + cmpi.b %d1,&ZERO + beq.w srem_zro + cmpi.b %d1,&INF + beq.l t_operr + cmpi.b %d1,&DENORM + beq.l srem_fpn + bra.l dst_qnan + +######################################################################### + + global sscale_snorm + global sscale_sdnrm +sscale_snorm: +sscale_sdnrm: + mov.b DTAG(%a6),%d1 + beq.l sscale + cmpi.b %d1,&ZERO + beq.l dst_zero + cmpi.b %d1,&INF + beq.l dst_inf + cmpi.b %d1,&DENORM + beq.l sscale + bra.l dst_qnan + + global sscale_szero +sscale_szero: + mov.b DTAG(%a6),%d1 + beq.l sscale + cmpi.b %d1,&ZERO + beq.l dst_zero + cmpi.b %d1,&INF + beq.l dst_inf + cmpi.b %d1,&DENORM + beq.l sscale + bra.l dst_qnan + + global sscale_sinf +sscale_sinf: + mov.b DTAG(%a6),%d1 + beq.l t_operr + cmpi.b %d1,&QNAN + beq.l dst_qnan + bra.l t_operr + +######################################################################## + + global sop_sqnan +sop_sqnan: + mov.b DTAG(%a6),%d1 + cmpi.b %d1,&QNAN + beq.l dst_qnan + bra.l src_qnan + +######################################################################### +# norm(): normalize the mantissa of an extended precision input. the # +# input operand should not be normalized already. # +# # +# XDEF **************************************************************** # +# norm() # +# # +# XREF **************************************************************** # +# none # +# # +# INPUT *************************************************************** # +# a0 = pointer fp extended precision operand to normalize # +# # +# OUTPUT ************************************************************** # +# d0 = number of bit positions the mantissa was shifted # +# a0 = the input operand's mantissa is normalized; the exponent # +# is unchanged. # +# # +######################################################################### + global norm +norm: + mov.l %d2, -(%sp) # create some temp regs + mov.l %d3, -(%sp) + + mov.l FTEMP_HI(%a0), %d0 # load hi(mantissa) + mov.l FTEMP_LO(%a0), %d1 # load lo(mantissa) + + bfffo %d0{&0:&32}, %d2 # how many places to shift? + beq.b norm_lo # hi(man) is all zeroes! + +norm_hi: + lsl.l %d2, %d0 # left shift hi(man) + bfextu %d1{&0:%d2}, %d3 # extract lo bits + + or.l %d3, %d0 # create hi(man) + lsl.l %d2, %d1 # create lo(man) + + mov.l %d0, FTEMP_HI(%a0) # store new hi(man) + mov.l %d1, FTEMP_LO(%a0) # store new lo(man) + + mov.l %d2, %d0 # return shift amount + + mov.l (%sp)+, %d3 # restore temp regs + mov.l (%sp)+, %d2 + + rts + +norm_lo: + bfffo %d1{&0:&32}, %d2 # how many places to shift? + lsl.l %d2, %d1 # shift lo(man) + add.l &32, %d2 # add 32 to shft amount + + mov.l %d1, FTEMP_HI(%a0) # store hi(man) + clr.l FTEMP_LO(%a0) # lo(man) is now zero + + mov.l %d2, %d0 # return shift amount + + mov.l (%sp)+, %d3 # restore temp regs + mov.l (%sp)+, %d2 + + rts + +######################################################################### +# unnorm_fix(): - changes an UNNORM to one of NORM, DENORM, or ZERO # +# - returns corresponding optype tag # +# # +# XDEF **************************************************************** # +# unnorm_fix() # +# # +# XREF **************************************************************** # +# norm() - normalize the mantissa # +# # +# INPUT *************************************************************** # +# a0 = pointer to unnormalized extended precision number # +# # +# OUTPUT ************************************************************** # +# d0 = optype tag - is corrected to one of NORM, DENORM, or ZERO # +# a0 = input operand has been converted to a norm, denorm, or # +# zero; both the exponent and mantissa are changed. # +# # +######################################################################### + + global unnorm_fix +unnorm_fix: + bfffo FTEMP_HI(%a0){&0:&32}, %d0 # how many shifts are needed? + bne.b unnorm_shift # hi(man) is not all zeroes + +# +# hi(man) is all zeroes so see if any bits in lo(man) are set +# +unnorm_chk_lo: + bfffo FTEMP_LO(%a0){&0:&32}, %d0 # is operand really a zero? + beq.w unnorm_zero # yes + + add.w &32, %d0 # no; fix shift distance + +# +# d0 = # shifts needed for complete normalization +# +unnorm_shift: + clr.l %d1 # clear top word + mov.w FTEMP_EX(%a0), %d1 # extract exponent + and.w &0x7fff, %d1 # strip off sgn + + cmp.w %d0, %d1 # will denorm push exp < 0? + bgt.b unnorm_nrm_zero # yes; denorm only until exp = 0 + +# +# exponent would not go < 0. therefore, number stays normalized +# + sub.w %d0, %d1 # shift exponent value + mov.w FTEMP_EX(%a0), %d0 # load old exponent + and.w &0x8000, %d0 # save old sign + or.w %d0, %d1 # {sgn,new exp} + mov.w %d1, FTEMP_EX(%a0) # insert new exponent + + bsr.l norm # normalize UNNORM + + mov.b &NORM, %d0 # return new optype tag + rts + +# +# exponent would go < 0, so only denormalize until exp = 0 +# +unnorm_nrm_zero: + cmp.b %d1, &32 # is exp <= 32? + bgt.b unnorm_nrm_zero_lrg # no; go handle large exponent + + bfextu FTEMP_HI(%a0){%d1:&32}, %d0 # extract new hi(man) + mov.l %d0, FTEMP_HI(%a0) # save new hi(man) + + mov.l FTEMP_LO(%a0), %d0 # fetch old lo(man) + lsl.l %d1, %d0 # extract new lo(man) + mov.l %d0, FTEMP_LO(%a0) # save new lo(man) + + and.w &0x8000, FTEMP_EX(%a0) # set exp = 0 + + mov.b &DENORM, %d0 # return new optype tag + rts + +# +# only mantissa bits set are in lo(man) +# +unnorm_nrm_zero_lrg: + sub.w &32, %d1 # adjust shft amt by 32 + + mov.l FTEMP_LO(%a0), %d0 # fetch old lo(man) + lsl.l %d1, %d0 # left shift lo(man) + + mov.l %d0, FTEMP_HI(%a0) # store new hi(man) + clr.l FTEMP_LO(%a0) # lo(man) = 0 + + and.w &0x8000, FTEMP_EX(%a0) # set exp = 0 + + mov.b &DENORM, %d0 # return new optype tag + rts + +# +# whole mantissa is zero so this UNNORM is actually a zero +# +unnorm_zero: + and.w &0x8000, FTEMP_EX(%a0) # force exponent to zero + + mov.b &ZERO, %d0 # fix optype tag + rts diff -u --recursive --new-file v2.4.0-test12/linux/arch/m68k/ifpsp060/src/fpsp.S linux/arch/m68k/ifpsp060/src/fpsp.S --- v2.4.0-test12/linux/arch/m68k/ifpsp060/src/fpsp.S Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/ifpsp060/src/fpsp.S Fri Dec 29 14:07:20 2000 @@ -0,0 +1,24785 @@ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP +M68000 Hi-Performance Microprocessor Division +M68060 Software Package +Production Release P1.00 -- October 10, 1994 + +M68060 Software Package Copyright © 1993, 1994 Motorola Inc. All rights reserved. + +THE SOFTWARE is provided on an "AS IS" basis and without warranty. +To the maximum extent permitted by applicable law, +MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, +INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE +and any warranty against infringement with regard to the SOFTWARE +(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials. + +To the maximum extent permitted by applicable law, +IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER +(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, +BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) +ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE. +Motorola assumes no responsibility for the maintenance and support of the SOFTWARE. + +You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE +so long as this entire notice is retained without alteration in any modified and/or +redistributed versions, and that such modified versions are clearly identified as such. +No licenses are granted by implication, estoppel or otherwise under any patents +or trademarks of Motorola, Inc. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# freal.s: +# This file is appended to the top of the 060FPSP package +# and contains the entry points into the package. The user, in +# effect, branches to one of the branch table entries located +# after _060FPSP_TABLE. +# Also, subroutine stubs exist in this file (_fpsp_done for +# example) that are referenced by the FPSP package itself in order +# to call a given routine. The stub routine actually performs the +# callout. The FPSP code does a "bsr" to the stub routine. This +# extra layer of hierarchy adds a slight performance penalty but +# it makes the FPSP code easier to read and more mainatinable. +# + +set _off_bsun, 0x00 +set _off_snan, 0x04 +set _off_operr, 0x08 +set _off_ovfl, 0x0c +set _off_unfl, 0x10 +set _off_dz, 0x14 +set _off_inex, 0x18 +set _off_fline, 0x1c +set _off_fpu_dis, 0x20 +set _off_trap, 0x24 +set _off_trace, 0x28 +set _off_access, 0x2c +set _off_done, 0x30 + +set _off_imr, 0x40 +set _off_dmr, 0x44 +set _off_dmw, 0x48 +set _off_irw, 0x4c +set _off_irl, 0x50 +set _off_drb, 0x54 +set _off_drw, 0x58 +set _off_drl, 0x5c +set _off_dwb, 0x60 +set _off_dww, 0x64 +set _off_dwl, 0x68 + +_060FPSP_TABLE: + +############################################################### + +# Here's the table of ENTRY POINTS for those linking the package. + bra.l _fpsp_snan + short 0x0000 + bra.l _fpsp_operr + short 0x0000 + bra.l _fpsp_ovfl + short 0x0000 + bra.l _fpsp_unfl + short 0x0000 + bra.l _fpsp_dz + short 0x0000 + bra.l _fpsp_inex + short 0x0000 + bra.l _fpsp_fline + short 0x0000 + bra.l _fpsp_unsupp + short 0x0000 + bra.l _fpsp_effadd + short 0x0000 + + space 56 + +############################################################### + global _fpsp_done +_fpsp_done: + mov.l %d0,-(%sp) + mov.l (_060FPSP_TABLE-0x80+_off_done,%pc),%d0 + pea.l (_060FPSP_TABLE-0x80,%pc,%d0) + mov.l 0x4(%sp),%d0 + rtd &0x4 + + global _real_ovfl +_real_ovfl: + mov.l %d0,-(%sp) + mov.l (_060FPSP_TABLE-0x80+_off_ovfl,%pc),%d0 + pea.l (_060FPSP_TABLE-0x80,%pc,%d0) + mov.l 0x4(%sp),%d0 + rtd &0x4 + + global _real_unfl +_real_unfl: + mov.l %d0,-(%sp) + mov.l (_060FPSP_TABLE-0x80+_off_unfl,%pc),%d0 + pea.l (_060FPSP_TABLE-0x80,%pc,%d0) + mov.l 0x4(%sp),%d0 + rtd &0x4 + + global _real_inex +_real_inex: + mov.l %d0,-(%sp) + mov.l (_060FPSP_TABLE-0x80+_off_inex,%pc),%d0 + pea.l (_060FPSP_TABLE-0x80,%pc,%d0) + mov.l 0x4(%sp),%d0 + rtd &0x4 + + global _real_bsun +_real_bsun: + mov.l %d0,-(%sp) + mov.l (_060FPSP_TABLE-0x80+_off_bsun,%pc),%d0 + pea.l (_060FPSP_TABLE-0x80,%pc,%d0) + mov.l 0x4(%sp),%d0 + rtd &0x4 + + global _real_operr +_real_operr: + mov.l %d0,-(%sp) + mov.l (_060FPSP_TABLE-0x80+_off_operr,%pc),%d0 + pea.l (_060FPSP_TABLE-0x80,%pc,%d0) + mov.l 0x4(%sp),%d0 + rtd &0x4 + + global _real_snan +_real_snan: + mov.l %d0,-(%sp) + mov.l (_060FPSP_TABLE-0x80+_off_snan,%pc),%d0 + pea.l (_060FPSP_TABLE-0x80,%pc,%d0) + mov.l 0x4(%sp),%d0 + rtd &0x4 + + global _real_dz +_real_dz: + mov.l %d0,-(%sp) + mov.l (_060FPSP_TABLE-0x80+_off_dz,%pc),%d0 + pea.l (_060FPSP_TABLE-0x80,%pc,%d0) + mov.l 0x4(%sp),%d0 + rtd &0x4 + + global _real_fline +_real_fline: + mov.l %d0,-(%sp) + mov.l (_060FPSP_TABLE-0x80+_off_fline,%pc),%d0 + pea.l (_060FPSP_TABLE-0x80,%pc,%d0) + mov.l 0x4(%sp),%d0 + rtd &0x4 + + global _real_fpu_disabled +_real_fpu_disabled: + mov.l %d0,-(%sp) + mov.l (_060FPSP_TABLE-0x80+_off_fpu_dis,%pc),%d0 + pea.l (_060FPSP_TABLE-0x80,%pc,%d0) + mov.l 0x4(%sp),%d0 + rtd &0x4 + + global _real_trap +_real_trap: + mov.l %d0,-(%sp) + mov.l (_060FPSP_TABLE-0x80+_off_trap,%pc),%d0 + pea.l (_060FPSP_TABLE-0x80,%pc,%d0) + mov.l 0x4(%sp),%d0 + rtd &0x4 + + global _real_trace +_real_trace: + mov.l %d0,-(%sp) + mov.l (_060FPSP_TABLE-0x80+_off_trace,%pc),%d0 + pea.l (_060FPSP_TABLE-0x80,%pc,%d0) + mov.l 0x4(%sp),%d0 + rtd &0x4 + + global _real_access +_real_access: + mov.l %d0,-(%sp) + mov.l (_060FPSP_TABLE-0x80+_off_access,%pc),%d0 + pea.l (_060FPSP_TABLE-0x80,%pc,%d0) + mov.l 0x4(%sp),%d0 + rtd &0x4 + +####################################### + + global _imem_read +_imem_read: + mov.l %d0,-(%sp) + mov.l (_060FPSP_TABLE-0x80+_off_imr,%pc),%d0 + pea.l (_060FPSP_TABLE-0x80,%pc,%d0) + mov.l 0x4(%sp),%d0 + rtd &0x4 + + global _dmem_read +_dmem_read: + mov.l %d0,-(%sp) + mov.l (_060FPSP_TABLE-0x80+_off_dmr,%pc),%d0 + pea.l (_060FPSP_TABLE-0x80,%pc,%d0) + mov.l 0x4(%sp),%d0 + rtd &0x4 + + global _dmem_write +_dmem_write: + mov.l %d0,-(%sp) + mov.l (_060FPSP_TABLE-0x80+_off_dmw,%pc),%d0 + pea.l (_060FPSP_TABLE-0x80,%pc,%d0) + mov.l 0x4(%sp),%d0 + rtd &0x4 + + global _imem_read_word +_imem_read_word: + mov.l %d0,-(%sp) + mov.l (_060FPSP_TABLE-0x80+_off_irw,%pc),%d0 + pea.l (_060FPSP_TABLE-0x80,%pc,%d0) + mov.l 0x4(%sp),%d0 + rtd &0x4 + + global _imem_read_long +_imem_read_long: + mov.l %d0,-(%sp) + mov.l (_060FPSP_TABLE-0x80+_off_irl,%pc),%d0 + pea.l (_060FPSP_TABLE-0x80,%pc,%d0) + mov.l 0x4(%sp),%d0 + rtd &0x4 + + global _dmem_read_byte +_dmem_read_byte: + mov.l %d0,-(%sp) + mov.l (_060FPSP_TABLE-0x80+_off_drb,%pc),%d0 + pea.l (_060FPSP_TABLE-0x80,%pc,%d0) + mov.l 0x4(%sp),%d0 + rtd &0x4 + + global _dmem_read_word +_dmem_read_word: + mov.l %d0,-(%sp) + mov.l (_060FPSP_TABLE-0x80+_off_drw,%pc),%d0 + pea.l (_060FPSP_TABLE-0x80,%pc,%d0) + mov.l 0x4(%sp),%d0 + rtd &0x4 + + global _dmem_read_long +_dmem_read_long: + mov.l %d0,-(%sp) + mov.l (_060FPSP_TABLE-0x80+_off_drl,%pc),%d0 + pea.l (_060FPSP_TABLE-0x80,%pc,%d0) + mov.l 0x4(%sp),%d0 + rtd &0x4 + + global _dmem_write_byte +_dmem_write_byte: + mov.l %d0,-(%sp) + mov.l (_060FPSP_TABLE-0x80+_off_dwb,%pc),%d0 + pea.l (_060FPSP_TABLE-0x80,%pc,%d0) + mov.l 0x4(%sp),%d0 + rtd &0x4 + + global _dmem_write_word +_dmem_write_word: + mov.l %d0,-(%sp) + mov.l (_060FPSP_TABLE-0x80+_off_dww,%pc),%d0 + pea.l (_060FPSP_TABLE-0x80,%pc,%d0) + mov.l 0x4(%sp),%d0 + rtd &0x4 + + global _dmem_write_long +_dmem_write_long: + mov.l %d0,-(%sp) + mov.l (_060FPSP_TABLE-0x80+_off_dwl,%pc),%d0 + pea.l (_060FPSP_TABLE-0x80,%pc,%d0) + mov.l 0x4(%sp),%d0 + rtd &0x4 + +# +# This file contains a set of define statements for constants +# in order to promote readability within the corecode itself. +# + +set LOCAL_SIZE, 192 # stack frame size(bytes) +set LV, -LOCAL_SIZE # stack offset + +set EXC_SR, 0x4 # stack status register +set EXC_PC, 0x6 # stack pc +set EXC_VOFF, 0xa # stacked vector offset +set EXC_EA, 0xc # stacked + +set EXC_FP, 0x0 # frame pointer + +set EXC_AREGS, -68 # offset of all address regs +set EXC_DREGS, -100 # offset of all data regs +set EXC_FPREGS, -36 # offset of all fp regs + +set EXC_A7, EXC_AREGS+(7*4) # offset of saved a7 +set OLD_A7, EXC_AREGS+(6*4) # extra copy of saved a7 +set EXC_A6, EXC_AREGS+(6*4) # offset of saved a6 +set EXC_A5, EXC_AREGS+(5*4) +set EXC_A4, EXC_AREGS+(4*4) +set EXC_A3, EXC_AREGS+(3*4) +set EXC_A2, EXC_AREGS+(2*4) +set EXC_A1, EXC_AREGS+(1*4) +set EXC_A0, EXC_AREGS+(0*4) +set EXC_D7, EXC_DREGS+(7*4) +set EXC_D6, EXC_DREGS+(6*4) +set EXC_D5, EXC_DREGS+(5*4) +set EXC_D4, EXC_DREGS+(4*4) +set EXC_D3, EXC_DREGS+(3*4) +set EXC_D2, EXC_DREGS+(2*4) +set EXC_D1, EXC_DREGS+(1*4) +set EXC_D0, EXC_DREGS+(0*4) + +set EXC_FP0, EXC_FPREGS+(0*12) # offset of saved fp0 +set EXC_FP1, EXC_FPREGS+(1*12) # offset of saved fp1 +set EXC_FP2, EXC_FPREGS+(2*12) # offset of saved fp2 (not used) + +set FP_SCR1, LV+80 # fp scratch 1 +set FP_SCR1_EX, FP_SCR1+0 +set FP_SCR1_SGN, FP_SCR1+2 +set FP_SCR1_HI, FP_SCR1+4 +set FP_SCR1_LO, FP_SCR1+8 + +set FP_SCR0, LV+68 # fp scratch 0 +set FP_SCR0_EX, FP_SCR0+0 +set FP_SCR0_SGN, FP_SCR0+2 +set FP_SCR0_HI, FP_SCR0+4 +set FP_SCR0_LO, FP_SCR0+8 + +set FP_DST, LV+56 # fp destination operand +set FP_DST_EX, FP_DST+0 +set FP_DST_SGN, FP_DST+2 +set FP_DST_HI, FP_DST+4 +set FP_DST_LO, FP_DST+8 + +set FP_SRC, LV+44 # fp source operand +set FP_SRC_EX, FP_SRC+0 +set FP_SRC_SGN, FP_SRC+2 +set FP_SRC_HI, FP_SRC+4 +set FP_SRC_LO, FP_SRC+8 + +set USER_FPIAR, LV+40 # FP instr address register + +set USER_FPSR, LV+36 # FP status register +set FPSR_CC, USER_FPSR+0 # FPSR condition codes +set FPSR_QBYTE, USER_FPSR+1 # FPSR qoutient byte +set FPSR_EXCEPT, USER_FPSR+2 # FPSR exception status byte +set FPSR_AEXCEPT, USER_FPSR+3 # FPSR accrued exception byte + +set USER_FPCR, LV+32 # FP control register +set FPCR_ENABLE, USER_FPCR+2 # FPCR exception enable +set FPCR_MODE, USER_FPCR+3 # FPCR rounding mode control + +set L_SCR3, LV+28 # integer scratch 3 +set L_SCR2, LV+24 # integer scratch 2 +set L_SCR1, LV+20 # integer scratch 1 + +set STORE_FLG, LV+19 # flag: operand store (ie. not fcmp/ftst) + +set EXC_TEMP2, LV+24 # temporary space +set EXC_TEMP, LV+16 # temporary space + +set DTAG, LV+15 # destination operand type +set STAG, LV+14 # source operand type + +set SPCOND_FLG, LV+10 # flag: special case (see below) + +set EXC_CC, LV+8 # saved condition codes +set EXC_EXTWPTR, LV+4 # saved current PC (active) +set EXC_EXTWORD, LV+2 # saved extension word +set EXC_CMDREG, LV+2 # saved extension word +set EXC_OPWORD, LV+0 # saved operation word + +################################ + +# Helpful macros + +set FTEMP, 0 # offsets within an +set FTEMP_EX, 0 # extended precision +set FTEMP_SGN, 2 # value saved in memory. +set FTEMP_HI, 4 +set FTEMP_LO, 8 +set FTEMP_GRS, 12 + +set LOCAL, 0 # offsets within an +set LOCAL_EX, 0 # extended precision +set LOCAL_SGN, 2 # value saved in memory. +set LOCAL_HI, 4 +set LOCAL_LO, 8 +set LOCAL_GRS, 12 + +set DST, 0 # offsets within an +set DST_EX, 0 # extended precision +set DST_HI, 4 # value saved in memory. +set DST_LO, 8 + +set SRC, 0 # offsets within an +set SRC_EX, 0 # extended precision +set SRC_HI, 4 # value saved in memory. +set SRC_LO, 8 + +set SGL_LO, 0x3f81 # min sgl prec exponent +set SGL_HI, 0x407e # max sgl prec exponent +set DBL_LO, 0x3c01 # min dbl prec exponent +set DBL_HI, 0x43fe # max dbl prec exponent +set EXT_LO, 0x0 # min ext prec exponent +set EXT_HI, 0x7ffe # max ext prec exponent + +set EXT_BIAS, 0x3fff # extended precision bias +set SGL_BIAS, 0x007f # single precision bias +set DBL_BIAS, 0x03ff # double precision bias + +set NORM, 0x00 # operand type for STAG/DTAG +set ZERO, 0x01 # operand type for STAG/DTAG +set INF, 0x02 # operand type for STAG/DTAG +set QNAN, 0x03 # operand type for STAG/DTAG +set DENORM, 0x04 # operand type for STAG/DTAG +set SNAN, 0x05 # operand type for STAG/DTAG +set UNNORM, 0x06 # operand type for STAG/DTAG + +################## +# FPSR/FPCR bits # +################## +set neg_bit, 0x3 # negative result +set z_bit, 0x2 # zero result +set inf_bit, 0x1 # infinite result +set nan_bit, 0x0 # NAN result + +set q_sn_bit, 0x7 # sign bit of quotient byte + +set bsun_bit, 7 # branch on unordered +set snan_bit, 6 # signalling NAN +set operr_bit, 5 # operand error +set ovfl_bit, 4 # overflow +set unfl_bit, 3 # underflow +set dz_bit, 2 # divide by zero +set inex2_bit, 1 # inexact result 2 +set inex1_bit, 0 # inexact result 1 + +set aiop_bit, 7 # accrued inexact operation bit +set aovfl_bit, 6 # accrued overflow bit +set aunfl_bit, 5 # accrued underflow bit +set adz_bit, 4 # accrued dz bit +set ainex_bit, 3 # accrued inexact bit + +############################# +# FPSR individual bit masks # +############################# +set neg_mask, 0x08000000 # negative bit mask (lw) +set inf_mask, 0x02000000 # infinity bit mask (lw) +set z_mask, 0x04000000 # zero bit mask (lw) +set nan_mask, 0x01000000 # nan bit mask (lw) + +set neg_bmask, 0x08 # negative bit mask (byte) +set inf_bmask, 0x02 # infinity bit mask (byte) +set z_bmask, 0x04 # zero bit mask (byte) +set nan_bmask, 0x01 # nan bit mask (byte) + +set bsun_mask, 0x00008000 # bsun exception mask +set snan_mask, 0x00004000 # snan exception mask +set operr_mask, 0x00002000 # operr exception mask +set ovfl_mask, 0x00001000 # overflow exception mask +set unfl_mask, 0x00000800 # underflow exception mask +set dz_mask, 0x00000400 # dz exception mask +set inex2_mask, 0x00000200 # inex2 exception mask +set inex1_mask, 0x00000100 # inex1 exception mask + +set aiop_mask, 0x00000080 # accrued illegal operation +set aovfl_mask, 0x00000040 # accrued overflow +set aunfl_mask, 0x00000020 # accrued underflow +set adz_mask, 0x00000010 # accrued divide by zero +set ainex_mask, 0x00000008 # accrued inexact + +###################################### +# FPSR combinations used in the FPSP # +###################################### +set dzinf_mask, inf_mask+dz_mask+adz_mask +set opnan_mask, nan_mask+operr_mask+aiop_mask +set nzi_mask, 0x01ffffff #clears N, Z, and I +set unfinx_mask, unfl_mask+inex2_mask+aunfl_mask+ainex_mask +set unf2inx_mask, unfl_mask+inex2_mask+ainex_mask +set ovfinx_mask, ovfl_mask+inex2_mask+aovfl_mask+ainex_mask +set inx1a_mask, inex1_mask+ainex_mask +set inx2a_mask, inex2_mask+ainex_mask +set snaniop_mask, nan_mask+snan_mask+aiop_mask +set snaniop2_mask, snan_mask+aiop_mask +set naniop_mask, nan_mask+aiop_mask +set neginf_mask, neg_mask+inf_mask +set infaiop_mask, inf_mask+aiop_mask +set negz_mask, neg_mask+z_mask +set opaop_mask, operr_mask+aiop_mask +set unfl_inx_mask, unfl_mask+aunfl_mask+ainex_mask +set ovfl_inx_mask, ovfl_mask+aovfl_mask+ainex_mask + +######### +# misc. # +######### +set rnd_stky_bit, 29 # stky bit pos in longword + +set sign_bit, 0x7 # sign bit +set signan_bit, 0x6 # signalling nan bit + +set sgl_thresh, 0x3f81 # minimum sgl exponent +set dbl_thresh, 0x3c01 # minimum dbl exponent + +set x_mode, 0x0 # extended precision +set s_mode, 0x4 # single precision +set d_mode, 0x8 # double precision + +set rn_mode, 0x0 # round-to-nearest +set rz_mode, 0x1 # round-to-zero +set rm_mode, 0x2 # round-tp-minus-infinity +set rp_mode, 0x3 # round-to-plus-infinity + +set mantissalen, 64 # length of mantissa in bits + +set BYTE, 1 # len(byte) == 1 byte +set WORD, 2 # len(word) == 2 bytes +set LONG, 4 # len(longword) == 2 bytes + +set BSUN_VEC, 0xc0 # bsun vector offset +set INEX_VEC, 0xc4 # inexact vector offset +set DZ_VEC, 0xc8 # dz vector offset +set UNFL_VEC, 0xcc # unfl vector offset +set OPERR_VEC, 0xd0 # operr vector offset +set OVFL_VEC, 0xd4 # ovfl vector offset +set SNAN_VEC, 0xd8 # snan vector offset + +########################### +# SPecial CONDition FLaGs # +########################### +set ftrapcc_flg, 0x01 # flag bit: ftrapcc exception +set fbsun_flg, 0x02 # flag bit: bsun exception +set mia7_flg, 0x04 # flag bit: (a7)+ +set mda7_flg, 0x08 # flag bit: -(a7) +set fmovm_flg, 0x40 # flag bit: fmovm instruction +set immed_flg, 0x80 # flag bit: & + +set ftrapcc_bit, 0x0 +set fbsun_bit, 0x1 +set mia7_bit, 0x2 +set mda7_bit, 0x3 +set immed_bit, 0x7 + +################################## +# TRANSCENDENTAL "LAST-OP" FLAGS # +################################## +set FMUL_OP, 0x0 # fmul instr performed last +set FDIV_OP, 0x1 # fdiv performed last +set FADD_OP, 0x2 # fadd performed last +set FMOV_OP, 0x3 # fmov performed last + +############# +# CONSTANTS # +############# +T1: long 0x40C62D38,0xD3D64634 # 16381 LOG2 LEAD +T2: long 0x3D6F90AE,0xB1E75CC7 # 16381 LOG2 TRAIL + +PI: long 0x40000000,0xC90FDAA2,0x2168C235,0x00000000 +PIBY2: long 0x3FFF0000,0xC90FDAA2,0x2168C235,0x00000000 + +TWOBYPI: + long 0x3FE45F30,0x6DC9C883 + +######################################################################### +# XDEF **************************************************************** # +# _fpsp_ovfl(): 060FPSP entry point for FP Overflow exception. # +# # +# This handler should be the first code executed upon taking the # +# FP Overflow exception in an operating system. # +# # +# XREF **************************************************************** # +# _imem_read_long() - read instruction longword # +# fix_skewed_ops() - adjust src operand in fsave frame # +# set_tag_x() - determine optype of src/dst operands # +# store_fpreg() - store opclass 0 or 2 result to FP regfile # +# unnorm_fix() - change UNNORM operands to NORM or ZERO # +# load_fpn2() - load dst operand from FP regfile # +# fout() - emulate an opclass 3 instruction # +# tbl_unsupp - add of table of emulation routines for opclass 0,2 # +# _fpsp_done() - "callout" for 060FPSP exit (all work done!) # +# _real_ovfl() - "callout" for Overflow exception enabled code # +# _real_inex() - "callout" for Inexact exception enabled code # +# _real_trace() - "callout" for Trace exception code # +# # +# INPUT *************************************************************** # +# - The system stack contains the FP Ovfl exception stack frame # +# - The fsave frame contains the source operand # +# # +# OUTPUT ************************************************************** # +# Overflow Exception enabled: # +# - The system stack is unchanged # +# - The fsave frame contains the adjusted src op for opclass 0,2 # +# Overflow Exception disabled: # +# - The system stack is unchanged # +# - The "exception present" flag in the fsave frame is cleared # +# # +# ALGORITHM *********************************************************** # +# On the 060, if an FP overflow is present as the result of any # +# instruction, the 060 will take an overflow exception whether the # +# exception is enabled or disabled in the FPCR. For the disabled case, # +# This handler emulates the instruction to determine what the correct # +# default result should be for the operation. This default result is # +# then stored in either the FP regfile, data regfile, or memory. # +# Finally, the handler exits through the "callout" _fpsp_done() # +# denoting that no exceptional conditions exist within the machine. # +# If the exception is enabled, then this handler must create the # +# exceptional operand and plave it in the fsave state frame, and store # +# the default result (only if the instruction is opclass 3). For # +# exceptions enabled, this handler must exit through the "callout" # +# _real_ovfl() so that the operating system enabled overflow handler # +# can handle this case. # +# Two other conditions exist. First, if overflow was disabled # +# but the inexact exception was enabled, this handler must exit # +# through the "callout" _real_inex() regardless of whether the result # +# was inexact. # +# Also, in the case of an opclass three instruction where # +# overflow was disabled and the trace exception was enabled, this # +# handler must exit through the "callout" _real_trace(). # +# # +######################################################################### + + global _fpsp_ovfl +_fpsp_ovfl: + +#$# sub.l &24,%sp # make room for src/dst + + link.w %a6,&-LOCAL_SIZE # init stack frame + + fsave FP_SRC(%a6) # grab the "busy" frame + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack + +# the FPIAR holds the "current PC" of the faulting instruction + mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6) + mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr + addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr + bsr.l _imem_read_long # fetch the instruction words + mov.l %d0,EXC_OPWORD(%a6) + +############################################################################## + + btst &0x5,EXC_CMDREG(%a6) # is instr an fmove out? + bne.w fovfl_out + + + lea FP_SRC(%a6),%a0 # pass: ptr to src op + bsr.l fix_skewed_ops # fix src op + +# since, I believe, only NORMs and DENORMs can come through here, +# maybe we can avoid the subroutine call. + lea FP_SRC(%a6),%a0 # pass: ptr to src op + bsr.l set_tag_x # tag the operand type + mov.b %d0,STAG(%a6) # maybe NORM,DENORM + +# bit five of the fp extension word separates the monadic and dyadic operations +# that can pass through fpsp_ovfl(). remember that fcmp, ftst, and fsincos +# will never take this exception. + btst &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic? + beq.b fovfl_extract # monadic + + bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg + bsr.l load_fpn2 # load dst into FP_DST + + lea FP_DST(%a6),%a0 # pass: ptr to dst op + bsr.l set_tag_x # tag the operand type + cmpi.b %d0,&UNNORM # is operand an UNNORM? + bne.b fovfl_op2_done # no + bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO +fovfl_op2_done: + mov.b %d0,DTAG(%a6) # save dst optype tag + +fovfl_extract: + +#$# mov.l FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6) +#$# mov.l FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6) +#$# mov.l FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6) +#$# mov.l FP_DST_EX(%a6),TRAP_DSTOP_EX(%a6) +#$# mov.l FP_DST_HI(%a6),TRAP_DSTOP_HI(%a6) +#$# mov.l FP_DST_LO(%a6),TRAP_DSTOP_LO(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd prec/mode + + mov.b 1+EXC_CMDREG(%a6),%d1 + andi.w &0x007f,%d1 # extract extension + + andi.l &0x00ff01ff,USER_FPSR(%a6) # zero all but accured field + + fmov.l &0x0,%fpcr # zero current control regs + fmov.l &0x0,%fpsr + + lea FP_SRC(%a6),%a0 + lea FP_DST(%a6),%a1 + +# maybe we can make these entry points ONLY the OVFL entry points of each routine. + mov.l (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr + jsr (tbl_unsupp.l,%pc,%d1.l*1) + +# the operation has been emulated. the result is in fp0. +# the EXOP, if an exception occurred, is in fp1. +# we must save the default result regardless of whether +# traps are enabled or disabled. + bfextu EXC_CMDREG(%a6){&6:&3},%d0 + bsr.l store_fpreg + +# the exceptional possibilities we have left ourselves with are ONLY overflow +# and inexact. and, the inexact is such that overflow occurred and was disabled +# but inexact was enabled. + btst &ovfl_bit,FPCR_ENABLE(%a6) + bne.b fovfl_ovfl_on + + btst &inex2_bit,FPCR_ENABLE(%a6) + bne.b fovfl_inex_on + + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + unlk %a6 +#$# add.l &24,%sp + bra.l _fpsp_done + +# overflow is enabled AND overflow, of course, occurred. so, we have the EXOP +# in fp1. now, simply jump to _real_ovfl()! +fovfl_ovfl_on: + fmovm.x &0x40,FP_SRC(%a6) # save EXOP (fp1) to stack + + mov.w &0xe005,2+FP_SRC(%a6) # save exc status + + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + frestore FP_SRC(%a6) # do this after fmovm,other fs! + + unlk %a6 + + bra.l _real_ovfl + +# overflow occurred but is disabled. meanwhile, inexact is enabled. therefore, +# we must jump to real_inex(). +fovfl_inex_on: + + fmovm.x &0x40,FP_SRC(%a6) # save EXOP (fp1) to stack + + mov.b &0xc4,1+EXC_VOFF(%a6) # vector offset = 0xc4 + mov.w &0xe001,2+FP_SRC(%a6) # save exc status + + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + frestore FP_SRC(%a6) # do this after fmovm,other fs! + + unlk %a6 + + bra.l _real_inex + +######################################################################## +fovfl_out: + + +#$# mov.l FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6) +#$# mov.l FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6) +#$# mov.l FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6) + +# the src operand is definitely a NORM(!), so tag it as such + mov.b &NORM,STAG(%a6) # set src optype tag + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd prec/mode + + and.l &0xffff00ff,USER_FPSR(%a6) # zero all but accured field + + fmov.l &0x0,%fpcr # zero current control regs + fmov.l &0x0,%fpsr + + lea FP_SRC(%a6),%a0 # pass ptr to src operand + + bsr.l fout + + btst &ovfl_bit,FPCR_ENABLE(%a6) + bne.w fovfl_ovfl_on + + btst &inex2_bit,FPCR_ENABLE(%a6) + bne.w fovfl_inex_on + + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + unlk %a6 +#$# add.l &24,%sp + + btst &0x7,(%sp) # is trace on? + beq.l _fpsp_done # no + + fmov.l %fpiar,0x8(%sp) # "Current PC" is in FPIAR + mov.w &0x2024,0x6(%sp) # stk fmt = 0x2; voff = 0x024 + bra.l _real_trace + +######################################################################### +# XDEF **************************************************************** # +# _fpsp_unfl(): 060FPSP entry point for FP Underflow exception. # +# # +# This handler should be the first code executed upon taking the # +# FP Underflow exception in an operating system. # +# # +# XREF **************************************************************** # +# _imem_read_long() - read instruction longword # +# fix_skewed_ops() - adjust src operand in fsave frame # +# set_tag_x() - determine optype of src/dst operands # +# store_fpreg() - store opclass 0 or 2 result to FP regfile # +# unnorm_fix() - change UNNORM operands to NORM or ZERO # +# load_fpn2() - load dst operand from FP regfile # +# fout() - emulate an opclass 3 instruction # +# tbl_unsupp - add of table of emulation routines for opclass 0,2 # +# _fpsp_done() - "callout" for 060FPSP exit (all work done!) # +# _real_ovfl() - "callout" for Overflow exception enabled code # +# _real_inex() - "callout" for Inexact exception enabled code # +# _real_trace() - "callout" for Trace exception code # +# # +# INPUT *************************************************************** # +# - The system stack contains the FP Unfl exception stack frame # +# - The fsave frame contains the source operand # +# # +# OUTPUT ************************************************************** # +# Underflow Exception enabled: # +# - The system stack is unchanged # +# - The fsave frame contains the adjusted src op for opclass 0,2 # +# Underflow Exception disabled: # +# - The system stack is unchanged # +# - The "exception present" flag in the fsave frame is cleared # +# # +# ALGORITHM *********************************************************** # +# On the 060, if an FP underflow is present as the result of any # +# instruction, the 060 will take an underflow exception whether the # +# exception is enabled or disabled in the FPCR. For the disabled case, # +# This handler emulates the instruction to determine what the correct # +# default result should be for the operation. This default result is # +# then stored in either the FP regfile, data regfile, or memory. # +# Finally, the handler exits through the "callout" _fpsp_done() # +# denoting that no exceptional conditions exist within the machine. # +# If the exception is enabled, then this handler must create the # +# exceptional operand and plave it in the fsave state frame, and store # +# the default result (only if the instruction is opclass 3). For # +# exceptions enabled, this handler must exit through the "callout" # +# _real_unfl() so that the operating system enabled overflow handler # +# can handle this case. # +# Two other conditions exist. First, if underflow was disabled # +# but the inexact exception was enabled and the result was inexact, # +# this handler must exit through the "callout" _real_inex(). # +# was inexact. # +# Also, in the case of an opclass three instruction where # +# underflow was disabled and the trace exception was enabled, this # +# handler must exit through the "callout" _real_trace(). # +# # +######################################################################### + + global _fpsp_unfl +_fpsp_unfl: + +#$# sub.l &24,%sp # make room for src/dst + + link.w %a6,&-LOCAL_SIZE # init stack frame + + fsave FP_SRC(%a6) # grab the "busy" frame + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack + +# the FPIAR holds the "current PC" of the faulting instruction + mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6) + mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr + addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr + bsr.l _imem_read_long # fetch the instruction words + mov.l %d0,EXC_OPWORD(%a6) + +############################################################################## + + btst &0x5,EXC_CMDREG(%a6) # is instr an fmove out? + bne.w funfl_out + + + lea FP_SRC(%a6),%a0 # pass: ptr to src op + bsr.l fix_skewed_ops # fix src op + + lea FP_SRC(%a6),%a0 # pass: ptr to src op + bsr.l set_tag_x # tag the operand type + mov.b %d0,STAG(%a6) # maybe NORM,DENORM + +# bit five of the fp ext word separates the monadic and dyadic operations +# that can pass through fpsp_unfl(). remember that fcmp, and ftst +# will never take this exception. + btst &0x5,1+EXC_CMDREG(%a6) # is op monadic or dyadic? + beq.b funfl_extract # monadic + +# now, what's left that's not dyadic is fsincos. we can distinguish it +# from all dyadics by the '0110xxx pattern + btst &0x4,1+EXC_CMDREG(%a6) # is op an fsincos? + bne.b funfl_extract # yes + + bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg + bsr.l load_fpn2 # load dst into FP_DST + + lea FP_DST(%a6),%a0 # pass: ptr to dst op + bsr.l set_tag_x # tag the operand type + cmpi.b %d0,&UNNORM # is operand an UNNORM? + bne.b funfl_op2_done # no + bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO +funfl_op2_done: + mov.b %d0,DTAG(%a6) # save dst optype tag + +funfl_extract: + +#$# mov.l FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6) +#$# mov.l FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6) +#$# mov.l FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6) +#$# mov.l FP_DST_EX(%a6),TRAP_DSTOP_EX(%a6) +#$# mov.l FP_DST_HI(%a6),TRAP_DSTOP_HI(%a6) +#$# mov.l FP_DST_LO(%a6),TRAP_DSTOP_LO(%a6) + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd prec/mode + + mov.b 1+EXC_CMDREG(%a6),%d1 + andi.w &0x007f,%d1 # extract extension + + andi.l &0x00ff01ff,USER_FPSR(%a6) + + fmov.l &0x0,%fpcr # zero current control regs + fmov.l &0x0,%fpsr + + lea FP_SRC(%a6),%a0 + lea FP_DST(%a6),%a1 + +# maybe we can make these entry points ONLY the OVFL entry points of each routine. + mov.l (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr + jsr (tbl_unsupp.l,%pc,%d1.l*1) + + bfextu EXC_CMDREG(%a6){&6:&3},%d0 + bsr.l store_fpreg + +# The `060 FPU multiplier hardware is such that if the result of a +# multiply operation is the smallest possible normalized number +# (0x00000000_80000000_00000000), then the machine will take an +# underflow exception. Since this is incorrect, we need to check +# if our emulation, after re-doing the operation, decided that +# no underflow was called for. We do these checks only in +# funfl_{unfl,inex}_on() because w/ both exceptions disabled, this +# special case will simply exit gracefully with the correct result. + +# the exceptional possibilities we have left ourselves with are ONLY overflow +# and inexact. and, the inexact is such that overflow occurred and was disabled +# but inexact was enabled. + btst &unfl_bit,FPCR_ENABLE(%a6) + bne.b funfl_unfl_on + +funfl_chkinex: + btst &inex2_bit,FPCR_ENABLE(%a6) + bne.b funfl_inex_on + +funfl_exit: + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + unlk %a6 +#$# add.l &24,%sp + bra.l _fpsp_done + +# overflow is enabled AND overflow, of course, occurred. so, we have the EXOP +# in fp1 (don't forget to save fp0). what to do now? +# well, we simply have to get to go to _real_unfl()! +funfl_unfl_on: + +# The `060 FPU multiplier hardware is such that if the result of a +# multiply operation is the smallest possible normalized number +# (0x00000000_80000000_00000000), then the machine will take an +# underflow exception. Since this is incorrect, we check here to see +# if our emulation, after re-doing the operation, decided that +# no underflow was called for. + btst &unfl_bit,FPSR_EXCEPT(%a6) + beq.w funfl_chkinex + +funfl_unfl_on2: + fmovm.x &0x40,FP_SRC(%a6) # save EXOP (fp1) to stack + + mov.w &0xe003,2+FP_SRC(%a6) # save exc status + + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + frestore FP_SRC(%a6) # do this after fmovm,other fs! + + unlk %a6 + + bra.l _real_unfl + +# undeflow occurred but is disabled. meanwhile, inexact is enabled. therefore, +# we must jump to real_inex(). +funfl_inex_on: + +# The `060 FPU multiplier hardware is such that if the result of a +# multiply operation is the smallest possible normalized number +# (0x00000000_80000000_00000000), then the machine will take an +# underflow exception. +# But, whether bogus or not, if inexact is enabled AND it occurred, +# then we have to branch to real_inex. + + btst &inex2_bit,FPSR_EXCEPT(%a6) + beq.w funfl_exit + +funfl_inex_on2: + + fmovm.x &0x40,FP_SRC(%a6) # save EXOP to stack + + mov.b &0xc4,1+EXC_VOFF(%a6) # vector offset = 0xc4 + mov.w &0xe001,2+FP_SRC(%a6) # save exc status + + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + frestore FP_SRC(%a6) # do this after fmovm,other fs! + + unlk %a6 + + bra.l _real_inex + +####################################################################### +funfl_out: + + +#$# mov.l FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6) +#$# mov.l FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6) +#$# mov.l FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6) + +# the src operand is definitely a NORM(!), so tag it as such + mov.b &NORM,STAG(%a6) # set src optype tag + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd prec/mode + + and.l &0xffff00ff,USER_FPSR(%a6) # zero all but accured field + + fmov.l &0x0,%fpcr # zero current control regs + fmov.l &0x0,%fpsr + + lea FP_SRC(%a6),%a0 # pass ptr to src operand + + bsr.l fout + + btst &unfl_bit,FPCR_ENABLE(%a6) + bne.w funfl_unfl_on2 + + btst &inex2_bit,FPCR_ENABLE(%a6) + bne.w funfl_inex_on2 + + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + unlk %a6 +#$# add.l &24,%sp + + btst &0x7,(%sp) # is trace on? + beq.l _fpsp_done # no + + fmov.l %fpiar,0x8(%sp) # "Current PC" is in FPIAR + mov.w &0x2024,0x6(%sp) # stk fmt = 0x2; voff = 0x024 + bra.l _real_trace + +######################################################################### +# XDEF **************************************************************** # +# _fpsp_unsupp(): 060FPSP entry point for FP "Unimplemented # +# Data Type" exception. # +# # +# This handler should be the first code executed upon taking the # +# FP Unimplemented Data Type exception in an operating system. # +# # +# XREF **************************************************************** # +# _imem_read_{word,long}() - read instruction word/longword # +# fix_skewed_ops() - adjust src operand in fsave frame # +# set_tag_x() - determine optype of src/dst operands # +# store_fpreg() - store opclass 0 or 2 result to FP regfile # +# unnorm_fix() - change UNNORM operands to NORM or ZERO # +# load_fpn2() - load dst operand from FP regfile # +# load_fpn1() - load src operand from FP regfile # +# fout() - emulate an opclass 3 instruction # +# tbl_unsupp - add of table of emulation routines for opclass 0,2 # +# _real_inex() - "callout" to operating system inexact handler # +# _fpsp_done() - "callout" for exit; work all done # +# _real_trace() - "callout" for Trace enabled exception # +# funimp_skew() - adjust fsave src ops to "incorrect" value # +# _real_snan() - "callout" for SNAN exception # +# _real_operr() - "callout" for OPERR exception # +# _real_ovfl() - "callout" for OVFL exception # +# _real_unfl() - "callout" for UNFL exception # +# get_packed() - fetch packed operand from memory # +# # +# INPUT *************************************************************** # +# - The system stack contains the "Unimp Data Type" stk frame # +# - The fsave frame contains the ssrc op (for UNNORM/DENORM) # +# # +# OUTPUT ************************************************************** # +# If Inexact exception (opclass 3): # +# - The system stack is changed to an Inexact exception stk frame # +# If SNAN exception (opclass 3): # +# - The system stack is changed to an SNAN exception stk frame # +# If OPERR exception (opclass 3): # +# - The system stack is changed to an OPERR exception stk frame # +# If OVFL exception (opclass 3): # +# - The system stack is changed to an OVFL exception stk frame # +# If UNFL exception (opclass 3): # +# - The system stack is changed to an UNFL exception stack frame # +# If Trace exception enabled: # +# - The system stack is changed to a Trace exception stack frame # +# Else: (normal case) # +# - Correct result has been stored as appropriate # +# # +# ALGORITHM *********************************************************** # +# Two main instruction types can enter here: (1) DENORM or UNNORM # +# unimplemented data types. These can be either opclass 0,2 or 3 # +# instructions, and (2) PACKED unimplemented data format instructions # +# also of opclasses 0,2, or 3. # +# For UNNORM/DENORM opclass 0 and 2, the handler fetches the src # +# operand from the fsave state frame and the dst operand (if dyadic) # +# from the FP register file. The instruction is then emulated by # +# choosing an emulation routine from a table of routines indexed by # +# instruction type. Once the instruction has been emulated and result # +# saved, then we check to see if any enabled exceptions resulted from # +# instruction emulation. If none, then we exit through the "callout" # +# _fpsp_done(). If there is an enabled FP exception, then we insert # +# this exception into the FPU in the fsave state frame and then exit # +# through _fpsp_done(). # +# PACKED opclass 0 and 2 is similar in how the instruction is # +# emulated and exceptions handled. The differences occur in how the # +# handler loads the packed op (by calling get_packed() routine) and # +# by the fact that a Trace exception could be pending for PACKED ops. # +# If a Trace exception is pending, then the current exception stack # +# frame is changed to a Trace exception stack frame and an exit is # +# made through _real_trace(). # +# For UNNORM/DENORM opclass 3, the actual move out to memory is # +# performed by calling the routine fout(). If no exception should occur # +# as the result of emulation, then an exit either occurs through # +# _fpsp_done() or through _real_trace() if a Trace exception is pending # +# (a Trace stack frame must be created here, too). If an FP exception # +# should occur, then we must create an exception stack frame of that # +# type and jump to either _real_snan(), _real_operr(), _real_inex(), # +# _real_unfl(), or _real_ovfl() as appropriate. PACKED opclass 3 # +# emulation is performed in a similar manner. # +# # +######################################################################### + +# +# (1) DENORM and UNNORM (unimplemented) data types: +# +# post-instruction +# ***************** +# * EA * +# pre-instruction * * +# ***************** ***************** +# * 0x0 * 0x0dc * * 0x3 * 0x0dc * +# ***************** ***************** +# * Next * * Next * +# * PC * * PC * +# ***************** ***************** +# * SR * * SR * +# ***************** ***************** +# +# (2) PACKED format (unsupported) opclasses two and three: +# ***************** +# * EA * +# * * +# ***************** +# * 0x2 * 0x0dc * +# ***************** +# * Next * +# * PC * +# ***************** +# * SR * +# ***************** +# + global _fpsp_unsupp +_fpsp_unsupp: + + link.w %a6,&-LOCAL_SIZE # init stack frame + + fsave FP_SRC(%a6) # save fp state + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack + + btst &0x5,EXC_SR(%a6) # user or supervisor mode? + bne.b fu_s +fu_u: + mov.l %usp,%a0 # fetch user stack pointer + mov.l %a0,EXC_A7(%a6) # save on stack + bra.b fu_cont +# if the exception is an opclass zero or two unimplemented data type +# exception, then the a7' calculated here is wrong since it doesn't +# stack an ea. however, we don't need an a7' for this case anyways. +fu_s: + lea 0x4+EXC_EA(%a6),%a0 # load old a7' + mov.l %a0,EXC_A7(%a6) # save on stack + +fu_cont: + +# the FPIAR holds the "current PC" of the faulting instruction +# the FPIAR should be set correctly for ALL exceptions passing through +# this point. + mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6) + mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr + addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr + bsr.l _imem_read_long # fetch the instruction words + mov.l %d0,EXC_OPWORD(%a6) # store OPWORD and EXTWORD + +############################ + + clr.b SPCOND_FLG(%a6) # clear special condition flag + +# Separate opclass three (fpn-to-mem) ops since they have a different +# stack frame and protocol. + btst &0x5,EXC_CMDREG(%a6) # is it an fmove out? + bne.w fu_out # yes + +# Separate packed opclass two instructions. + bfextu EXC_CMDREG(%a6){&0:&6},%d0 + cmpi.b %d0,&0x13 + beq.w fu_in_pack + + +# I'm not sure at this point what FPSR bits are valid for this instruction. +# so, since the emulation routines re-create them anyways, zero exception field + andi.l &0x00ff00ff,USER_FPSR(%a6) # zero exception field + + fmov.l &0x0,%fpcr # zero current control regs + fmov.l &0x0,%fpsr + +# Opclass two w/ memory-to-fpn operation will have an incorrect extended +# precision format if the src format was single or double and the +# source data type was an INF, NAN, DENORM, or UNNORM + lea FP_SRC(%a6),%a0 # pass ptr to input + bsr.l fix_skewed_ops + +# we don't know whether the src operand or the dst operand (or both) is the +# UNNORM or DENORM. call the function that tags the operand type. if the +# input is an UNNORM, then convert it to a NORM, DENORM, or ZERO. + lea FP_SRC(%a6),%a0 # pass: ptr to src op + bsr.l set_tag_x # tag the operand type + cmpi.b %d0,&UNNORM # is operand an UNNORM? + bne.b fu_op2 # no + bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO + +fu_op2: + mov.b %d0,STAG(%a6) # save src optype tag + + bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg + +# bit five of the fp extension word separates the monadic and dyadic operations +# at this point + btst &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic? + beq.b fu_extract # monadic + cmpi.b 1+EXC_CMDREG(%a6),&0x3a # is operation an ftst? + beq.b fu_extract # yes, so it's monadic, too + + bsr.l load_fpn2 # load dst into FP_DST + + lea FP_DST(%a6),%a0 # pass: ptr to dst op + bsr.l set_tag_x # tag the operand type + cmpi.b %d0,&UNNORM # is operand an UNNORM? + bne.b fu_op2_done # no + bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO +fu_op2_done: + mov.b %d0,DTAG(%a6) # save dst optype tag + +fu_extract: + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # fetch rnd mode/prec + + bfextu 1+EXC_CMDREG(%a6){&1:&7},%d1 # extract extension + + lea FP_SRC(%a6),%a0 + lea FP_DST(%a6),%a1 + + mov.l (tbl_unsupp.l,%pc,%d1.l*4),%d1 # fetch routine addr + jsr (tbl_unsupp.l,%pc,%d1.l*1) + +# +# Exceptions in order of precedence: +# BSUN : none +# SNAN : all dyadic ops +# OPERR : fsqrt(-NORM) +# OVFL : all except ftst,fcmp +# UNFL : all except ftst,fcmp +# DZ : fdiv +# INEX2 : all except ftst,fcmp +# INEX1 : none (packed doesn't go through here) +# + +# we determine the highest priority exception(if any) set by the +# emulation routine that has also been enabled by the user. + mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions set + bne.b fu_in_ena # some are enabled + +fu_in_cont: +# fcmp and ftst do not store any result. + mov.b 1+EXC_CMDREG(%a6),%d0 # fetch extension + andi.b &0x38,%d0 # extract bits 3-5 + cmpi.b %d0,&0x38 # is instr fcmp or ftst? + beq.b fu_in_exit # yes + + bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg + bsr.l store_fpreg # store the result + +fu_in_exit: + + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + unlk %a6 + + bra.l _fpsp_done + +fu_in_ena: + and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enabled + bfffo %d0{&24:&8},%d0 # find highest priority exception + bne.b fu_in_exc # there is at least one set + +# +# No exceptions occurred that were also enabled. Now: +# +# if (OVFL && ovfl_disabled && inexact_enabled) { +# branch to _real_inex() (even if the result was exact!); +# } else { +# save the result in the proper fp reg (unless the op is fcmp or ftst); +# return; +# } +# + btst &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set? + beq.b fu_in_cont # no + +fu_in_ovflchk: + btst &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled? + beq.b fu_in_cont # no + bra.w fu_in_exc_ovfl # go insert overflow frame + +# +# An exception occurred and that exception was enabled: +# +# shift enabled exception field into lo byte of d0; +# if (((INEX2 || INEX1) && inex_enabled && OVFL && ovfl_disabled) || +# ((INEX2 || INEX1) && inex_enabled && UNFL && unfl_disabled)) { +# /* +# * this is the case where we must call _real_inex() now or else +# * there will be no other way to pass it the exceptional operand +# */ +# call _real_inex(); +# } else { +# restore exc state (SNAN||OPERR||OVFL||UNFL||DZ||INEX) into the FPU; +# } +# +fu_in_exc: + subi.l &24,%d0 # fix offset to be 0-8 + cmpi.b %d0,&0x6 # is exception INEX? (6) + bne.b fu_in_exc_exit # no + +# the enabled exception was inexact + btst &unfl_bit,FPSR_EXCEPT(%a6) # did disabled underflow occur? + bne.w fu_in_exc_unfl # yes + btst &ovfl_bit,FPSR_EXCEPT(%a6) # did disabled overflow occur? + bne.w fu_in_exc_ovfl # yes + +# here, we insert the correct fsave status value into the fsave frame for the +# corresponding exception. the operand in the fsave frame should be the original +# src operand. +fu_in_exc_exit: + mov.l %d0,-(%sp) # save d0 + bsr.l funimp_skew # skew sgl or dbl inputs + mov.l (%sp)+,%d0 # restore d0 + + mov.w (tbl_except.b,%pc,%d0.w*2),2+FP_SRC(%a6) # create exc status + + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + frestore FP_SRC(%a6) # restore src op + + unlk %a6 + + bra.l _fpsp_done + +tbl_except: + short 0xe000,0xe006,0xe004,0xe005 + short 0xe003,0xe002,0xe001,0xe001 + +fu_in_exc_unfl: + mov.w &0x4,%d0 + bra.b fu_in_exc_exit +fu_in_exc_ovfl: + mov.w &0x03,%d0 + bra.b fu_in_exc_exit + +# If the input operand to this operation was opclass two and a single +# or double precision denorm, inf, or nan, the operand needs to be +# "corrected" in order to have the proper equivalent extended precision +# number. + global fix_skewed_ops +fix_skewed_ops: + bfextu EXC_CMDREG(%a6){&0:&6},%d0 # extract opclass,src fmt + cmpi.b %d0,&0x11 # is class = 2 & fmt = sgl? + beq.b fso_sgl # yes + cmpi.b %d0,&0x15 # is class = 2 & fmt = dbl? + beq.b fso_dbl # yes + rts # no + +fso_sgl: + mov.w LOCAL_EX(%a0),%d0 # fetch src exponent + andi.w &0x7fff,%d0 # strip sign + cmpi.w %d0,&0x3f80 # is |exp| == $3f80? + beq.b fso_sgl_dnrm_zero # yes + cmpi.w %d0,&0x407f # no; is |exp| == $407f? + beq.b fso_infnan # yes + rts # no + +fso_sgl_dnrm_zero: + andi.l &0x7fffffff,LOCAL_HI(%a0) # clear j-bit + beq.b fso_zero # it's a skewed zero +fso_sgl_dnrm: +# here, we count on norm not to alter a0... + bsr.l norm # normalize mantissa + neg.w %d0 # -shft amt + addi.w &0x3f81,%d0 # adjust new exponent + andi.w &0x8000,LOCAL_EX(%a0) # clear old exponent + or.w %d0,LOCAL_EX(%a0) # insert new exponent + rts + +fso_zero: + andi.w &0x8000,LOCAL_EX(%a0) # clear bogus exponent + rts + +fso_infnan: + andi.b &0x7f,LOCAL_HI(%a0) # clear j-bit + ori.w &0x7fff,LOCAL_EX(%a0) # make exponent = $7fff + rts + +fso_dbl: + mov.w LOCAL_EX(%a0),%d0 # fetch src exponent + andi.w &0x7fff,%d0 # strip sign + cmpi.w %d0,&0x3c00 # is |exp| == $3c00? + beq.b fso_dbl_dnrm_zero # yes + cmpi.w %d0,&0x43ff # no; is |exp| == $43ff? + beq.b fso_infnan # yes + rts # no + +fso_dbl_dnrm_zero: + andi.l &0x7fffffff,LOCAL_HI(%a0) # clear j-bit + bne.b fso_dbl_dnrm # it's a skewed denorm + tst.l LOCAL_LO(%a0) # is it a zero? + beq.b fso_zero # yes +fso_dbl_dnrm: +# here, we count on norm not to alter a0... + bsr.l norm # normalize mantissa + neg.w %d0 # -shft amt + addi.w &0x3c01,%d0 # adjust new exponent + andi.w &0x8000,LOCAL_EX(%a0) # clear old exponent + or.w %d0,LOCAL_EX(%a0) # insert new exponent + rts + +################################################################# + +# fmove out took an unimplemented data type exception. +# the src operand is in FP_SRC. Call _fout() to write out the result and +# to determine which exceptions, if any, to take. +fu_out: + +# Separate packed move outs from the UNNORM and DENORM move outs. + bfextu EXC_CMDREG(%a6){&3:&3},%d0 + cmpi.b %d0,&0x3 + beq.w fu_out_pack + cmpi.b %d0,&0x7 + beq.w fu_out_pack + + +# I'm not sure at this point what FPSR bits are valid for this instruction. +# so, since the emulation routines re-create them anyways, zero exception field. +# fmove out doesn't affect ccodes. + and.l &0xffff00ff,USER_FPSR(%a6) # zero exception field + + fmov.l &0x0,%fpcr # zero current control regs + fmov.l &0x0,%fpsr + +# the src can ONLY be a DENORM or an UNNORM! so, don't make any big subroutine +# call here. just figure out what it is... + mov.w FP_SRC_EX(%a6),%d0 # get exponent + andi.w &0x7fff,%d0 # strip sign + beq.b fu_out_denorm # it's a DENORM + + lea FP_SRC(%a6),%a0 + bsr.l unnorm_fix # yes; fix it + + mov.b %d0,STAG(%a6) + + bra.b fu_out_cont +fu_out_denorm: + mov.b &DENORM,STAG(%a6) +fu_out_cont: + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # fetch rnd mode/prec + + lea FP_SRC(%a6),%a0 # pass ptr to src operand + + mov.l (%a6),EXC_A6(%a6) # in case a6 changes + bsr.l fout # call fmove out routine + +# Exceptions in order of precedence: +# BSUN : none +# SNAN : none +# OPERR : fmove.{b,w,l} out of large UNNORM +# OVFL : fmove.{s,d} +# UNFL : fmove.{s,d,x} +# DZ : none +# INEX2 : all +# INEX1 : none (packed doesn't travel through here) + +# determine the highest priority exception(if any) set by the +# emulation routine that has also been enabled by the user. + mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions enabled + bne.w fu_out_ena # some are enabled + +fu_out_done: + + mov.l EXC_A6(%a6),(%a6) # in case a6 changed + +# on extended precision opclass three instructions using pre-decrement or +# post-increment addressing mode, the address register is not updated. is the +# address register was the stack pointer used from user mode, then let's update +# it here. if it was used from supervisor mode, then we have to handle this +# as a special case. + btst &0x5,EXC_SR(%a6) + bne.b fu_out_done_s + + mov.l EXC_A7(%a6),%a0 # restore a7 + mov.l %a0,%usp + +fu_out_done_cont: + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + unlk %a6 + + btst &0x7,(%sp) # is trace on? + bne.b fu_out_trace # yes + + bra.l _fpsp_done + +# is the ea mode pre-decrement of the stack pointer from supervisor mode? +# ("fmov.x fpm,-(a7)") if so, +fu_out_done_s: + cmpi.b SPCOND_FLG(%a6),&mda7_flg + bne.b fu_out_done_cont + +# the extended precision result is still in fp0. but, we need to save it +# somewhere on the stack until we can copy it to its final resting place. +# here, we're counting on the top of the stack to be the old place-holders +# for fp0/fp1 which have already been restored. that way, we can write +# over those destinations with the shifted stack frame. + fmovm.x &0x80,FP_SRC(%a6) # put answer on stack + + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + mov.l (%a6),%a6 # restore frame pointer + + mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp) + mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp) + +# now, copy the result to the proper place on the stack + mov.l LOCAL_SIZE+FP_SRC_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp) + mov.l LOCAL_SIZE+FP_SRC_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp) + mov.l LOCAL_SIZE+FP_SRC_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp) + + add.l &LOCAL_SIZE-0x8,%sp + + btst &0x7,(%sp) + bne.b fu_out_trace + + bra.l _fpsp_done + +fu_out_ena: + and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enabled + bfffo %d0{&24:&8},%d0 # find highest priority exception + bne.b fu_out_exc # there is at least one set + +# no exceptions were set. +# if a disabled overflow occurred and inexact was enabled but the result +# was exact, then a branch to _real_inex() is made. + btst &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set? + beq.w fu_out_done # no + +fu_out_ovflchk: + btst &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled? + beq.w fu_out_done # no + bra.w fu_inex # yes + +# +# The fp move out that took the "Unimplemented Data Type" exception was +# being traced. Since the stack frames are similar, get the "current" PC +# from FPIAR and put it in the trace stack frame then jump to _real_trace(). +# +# UNSUPP FRAME TRACE FRAME +# ***************** ***************** +# * EA * * Current * +# * * * PC * +# ***************** ***************** +# * 0x3 * 0x0dc * * 0x2 * 0x024 * +# ***************** ***************** +# * Next * * Next * +# * PC * * PC * +# ***************** ***************** +# * SR * * SR * +# ***************** ***************** +# +fu_out_trace: + mov.w &0x2024,0x6(%sp) + fmov.l %fpiar,0x8(%sp) + bra.l _real_trace + +# an exception occurred and that exception was enabled. +fu_out_exc: + subi.l &24,%d0 # fix offset to be 0-8 + +# we don't mess with the existing fsave frame. just re-insert it and +# jump to the "_real_{}()" handler... + mov.w (tbl_fu_out.b,%pc,%d0.w*2),%d0 + jmp (tbl_fu_out.b,%pc,%d0.w*1) + + swbeg &0x8 +tbl_fu_out: + short tbl_fu_out - tbl_fu_out # BSUN can't happen + short tbl_fu_out - tbl_fu_out # SNAN can't happen + short fu_operr - tbl_fu_out # OPERR + short fu_ovfl - tbl_fu_out # OVFL + short fu_unfl - tbl_fu_out # UNFL + short tbl_fu_out - tbl_fu_out # DZ can't happen + short fu_inex - tbl_fu_out # INEX2 + short tbl_fu_out - tbl_fu_out # INEX1 won't make it here + +# for snan,operr,ovfl,unfl, src op is still in FP_SRC so just +# frestore it. +fu_snan: + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + mov.w &0x30d8,EXC_VOFF(%a6) # vector offset = 0xd8 + mov.w &0xe006,2+FP_SRC(%a6) + + frestore FP_SRC(%a6) + + unlk %a6 + + + bra.l _real_snan + +fu_operr: + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + mov.w &0x30d0,EXC_VOFF(%a6) # vector offset = 0xd0 + mov.w &0xe004,2+FP_SRC(%a6) + + frestore FP_SRC(%a6) + + unlk %a6 + + + bra.l _real_operr + +fu_ovfl: + fmovm.x &0x40,FP_SRC(%a6) # save EXOP to the stack + + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + mov.w &0x30d4,EXC_VOFF(%a6) # vector offset = 0xd4 + mov.w &0xe005,2+FP_SRC(%a6) + + frestore FP_SRC(%a6) # restore EXOP + + unlk %a6 + + bra.l _real_ovfl + +# underflow can happen for extended precision. extended precision opclass +# three instruction exceptions don't update the stack pointer. so, if the +# exception occurred from user mode, then simply update a7 and exit normally. +# if the exception occurred from supervisor mode, check if +fu_unfl: + mov.l EXC_A6(%a6),(%a6) # restore a6 + + btst &0x5,EXC_SR(%a6) + bne.w fu_unfl_s + + mov.l EXC_A7(%a6),%a0 # restore a7 whether we need + mov.l %a0,%usp # to or not... + +fu_unfl_cont: + fmovm.x &0x40,FP_SRC(%a6) # save EXOP to the stack + + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + mov.w &0x30cc,EXC_VOFF(%a6) # vector offset = 0xcc + mov.w &0xe003,2+FP_SRC(%a6) + + frestore FP_SRC(%a6) # restore EXOP + + unlk %a6 + + bra.l _real_unfl + +fu_unfl_s: + cmpi.b SPCOND_FLG(%a6),&mda7_flg # was the mode -(sp)? + bne.b fu_unfl_cont + +# the extended precision result is still in fp0. but, we need to save it +# somewhere on the stack until we can copy it to its final resting place +# (where the exc frame is currently). make sure it's not at the top of the +# frame or it will get overwritten when the exc stack frame is shifted "down". + fmovm.x &0x80,FP_SRC(%a6) # put answer on stack + fmovm.x &0x40,FP_DST(%a6) # put EXOP on stack + + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + mov.w &0x30cc,EXC_VOFF(%a6) # vector offset = 0xcc + mov.w &0xe003,2+FP_DST(%a6) + + frestore FP_DST(%a6) # restore EXOP + + mov.l (%a6),%a6 # restore frame pointer + + mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp) + mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp) + mov.l LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp) + +# now, copy the result to the proper place on the stack + mov.l LOCAL_SIZE+FP_SRC_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp) + mov.l LOCAL_SIZE+FP_SRC_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp) + mov.l LOCAL_SIZE+FP_SRC_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp) + + add.l &LOCAL_SIZE-0x8,%sp + + bra.l _real_unfl + +# fmove in and out enter here. +fu_inex: + fmovm.x &0x40,FP_SRC(%a6) # save EXOP to the stack + + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + mov.w &0x30c4,EXC_VOFF(%a6) # vector offset = 0xc4 + mov.w &0xe001,2+FP_SRC(%a6) + + frestore FP_SRC(%a6) # restore EXOP + + unlk %a6 + + + bra.l _real_inex + +######################################################################### +######################################################################### +fu_in_pack: + + +# I'm not sure at this point what FPSR bits are valid for this instruction. +# so, since the emulation routines re-create them anyways, zero exception field + andi.l &0x0ff00ff,USER_FPSR(%a6) # zero exception field + + fmov.l &0x0,%fpcr # zero current control regs + fmov.l &0x0,%fpsr + + bsr.l get_packed # fetch packed src operand + + lea FP_SRC(%a6),%a0 # pass ptr to src + bsr.l set_tag_x # set src optype tag + + mov.b %d0,STAG(%a6) # save src optype tag + + bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg + +# bit five of the fp extension word separates the monadic and dyadic operations +# at this point + btst &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic? + beq.b fu_extract_p # monadic + cmpi.b 1+EXC_CMDREG(%a6),&0x3a # is operation an ftst? + beq.b fu_extract_p # yes, so it's monadic, too + + bsr.l load_fpn2 # load dst into FP_DST + + lea FP_DST(%a6),%a0 # pass: ptr to dst op + bsr.l set_tag_x # tag the operand type + cmpi.b %d0,&UNNORM # is operand an UNNORM? + bne.b fu_op2_done_p # no + bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO +fu_op2_done_p: + mov.b %d0,DTAG(%a6) # save dst optype tag + +fu_extract_p: + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # fetch rnd mode/prec + + bfextu 1+EXC_CMDREG(%a6){&1:&7},%d1 # extract extension + + lea FP_SRC(%a6),%a0 + lea FP_DST(%a6),%a1 + + mov.l (tbl_unsupp.l,%pc,%d1.l*4),%d1 # fetch routine addr + jsr (tbl_unsupp.l,%pc,%d1.l*1) + +# +# Exceptions in order of precedence: +# BSUN : none +# SNAN : all dyadic ops +# OPERR : fsqrt(-NORM) +# OVFL : all except ftst,fcmp +# UNFL : all except ftst,fcmp +# DZ : fdiv +# INEX2 : all except ftst,fcmp +# INEX1 : all +# + +# we determine the highest priority exception(if any) set by the +# emulation routine that has also been enabled by the user. + mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions enabled + bne.w fu_in_ena_p # some are enabled + +fu_in_cont_p: +# fcmp and ftst do not store any result. + mov.b 1+EXC_CMDREG(%a6),%d0 # fetch extension + andi.b &0x38,%d0 # extract bits 3-5 + cmpi.b %d0,&0x38 # is instr fcmp or ftst? + beq.b fu_in_exit_p # yes + + bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg + bsr.l store_fpreg # store the result + +fu_in_exit_p: + + btst &0x5,EXC_SR(%a6) # user or supervisor? + bne.w fu_in_exit_s_p # supervisor + + mov.l EXC_A7(%a6),%a0 # update user a7 + mov.l %a0,%usp + +fu_in_exit_cont_p: + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + unlk %a6 # unravel stack frame + + btst &0x7,(%sp) # is trace on? + bne.w fu_trace_p # yes + + bra.l _fpsp_done # exit to os + +# the exception occurred in supervisor mode. check to see if the +# addressing mode was (a7)+. if so, we'll need to shift the +# stack frame "up". +fu_in_exit_s_p: + btst &mia7_bit,SPCOND_FLG(%a6) # was ea mode (a7)+ + beq.b fu_in_exit_cont_p # no + + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + unlk %a6 # unravel stack frame + +# shift the stack frame "up". we don't really care about the field. + mov.l 0x4(%sp),0x10(%sp) + mov.l 0x0(%sp),0xc(%sp) + add.l &0xc,%sp + + btst &0x7,(%sp) # is trace on? + bne.w fu_trace_p # yes + + bra.l _fpsp_done # exit to os + +fu_in_ena_p: + and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enabled & set + bfffo %d0{&24:&8},%d0 # find highest priority exception + bne.b fu_in_exc_p # at least one was set + +# +# No exceptions occurred that were also enabled. Now: +# +# if (OVFL && ovfl_disabled && inexact_enabled) { +# branch to _real_inex() (even if the result was exact!); +# } else { +# save the result in the proper fp reg (unless the op is fcmp or ftst); +# return; +# } +# + btst &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set? + beq.w fu_in_cont_p # no + +fu_in_ovflchk_p: + btst &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled? + beq.w fu_in_cont_p # no + bra.w fu_in_exc_ovfl_p # do _real_inex() now + +# +# An exception occurred and that exception was enabled: +# +# shift enabled exception field into lo byte of d0; +# if (((INEX2 || INEX1) && inex_enabled && OVFL && ovfl_disabled) || +# ((INEX2 || INEX1) && inex_enabled && UNFL && unfl_disabled)) { +# /* +# * this is the case where we must call _real_inex() now or else +# * there will be no other way to pass it the exceptional operand +# */ +# call _real_inex(); +# } else { +# restore exc state (SNAN||OPERR||OVFL||UNFL||DZ||INEX) into the FPU; +# } +# +fu_in_exc_p: + subi.l &24,%d0 # fix offset to be 0-8 + cmpi.b %d0,&0x6 # is exception INEX? (6 or 7) + blt.b fu_in_exc_exit_p # no + +# the enabled exception was inexact + btst &unfl_bit,FPSR_EXCEPT(%a6) # did disabled underflow occur? + bne.w fu_in_exc_unfl_p # yes + btst &ovfl_bit,FPSR_EXCEPT(%a6) # did disabled overflow occur? + bne.w fu_in_exc_ovfl_p # yes + +# here, we insert the correct fsave status value into the fsave frame for the +# corresponding exception. the operand in the fsave frame should be the original +# src operand. +# as a reminder for future predicted pain and agony, we are passing in fsave the +# "non-skewed" operand for cases of sgl and dbl src INFs,NANs, and DENORMs. +# this is INCORRECT for enabled SNAN which would give to the user the skewed SNAN!!! +fu_in_exc_exit_p: + btst &0x5,EXC_SR(%a6) # user or supervisor? + bne.w fu_in_exc_exit_s_p # supervisor + + mov.l EXC_A7(%a6),%a0 # update user a7 + mov.l %a0,%usp + +fu_in_exc_exit_cont_p: + mov.w (tbl_except_p.b,%pc,%d0.w*2),2+FP_SRC(%a6) + + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + frestore FP_SRC(%a6) # restore src op + + unlk %a6 + + btst &0x7,(%sp) # is trace enabled? + bne.w fu_trace_p # yes + + bra.l _fpsp_done + +tbl_except_p: + short 0xe000,0xe006,0xe004,0xe005 + short 0xe003,0xe002,0xe001,0xe001 + +fu_in_exc_ovfl_p: + mov.w &0x3,%d0 + bra.w fu_in_exc_exit_p + +fu_in_exc_unfl_p: + mov.w &0x4,%d0 + bra.w fu_in_exc_exit_p + +fu_in_exc_exit_s_p: + btst &mia7_bit,SPCOND_FLG(%a6) + beq.b fu_in_exc_exit_cont_p + + mov.w (tbl_except_p.b,%pc,%d0.w*2),2+FP_SRC(%a6) + + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + frestore FP_SRC(%a6) # restore src op + + unlk %a6 # unravel stack frame + +# shift stack frame "up". who cares about field. + mov.l 0x4(%sp),0x10(%sp) + mov.l 0x0(%sp),0xc(%sp) + add.l &0xc,%sp + + btst &0x7,(%sp) # is trace on? + bne.b fu_trace_p # yes + + bra.l _fpsp_done # exit to os + +# +# The opclass two PACKED instruction that took an "Unimplemented Data Type" +# exception was being traced. Make the "current" PC the FPIAR and put it in the +# trace stack frame then jump to _real_trace(). +# +# UNSUPP FRAME TRACE FRAME +# ***************** ***************** +# * EA * * Current * +# * * * PC * +# ***************** ***************** +# * 0x2 * 0x0dc * * 0x2 * 0x024 * +# ***************** ***************** +# * Next * * Next * +# * PC * * PC * +# ***************** ***************** +# * SR * * SR * +# ***************** ***************** +fu_trace_p: + mov.w &0x2024,0x6(%sp) + fmov.l %fpiar,0x8(%sp) + + bra.l _real_trace + +######################################################### +######################################################### +fu_out_pack: + + +# I'm not sure at this point what FPSR bits are valid for this instruction. +# so, since the emulation routines re-create them anyways, zero exception field. +# fmove out doesn't affect ccodes. + and.l &0xffff00ff,USER_FPSR(%a6) # zero exception field + + fmov.l &0x0,%fpcr # zero current control regs + fmov.l &0x0,%fpsr + + bfextu EXC_CMDREG(%a6){&6:&3},%d0 + bsr.l load_fpn1 + +# unlike other opclass 3, unimplemented data type exceptions, packed must be +# able to detect all operand types. + lea FP_SRC(%a6),%a0 + bsr.l set_tag_x # tag the operand type + cmpi.b %d0,&UNNORM # is operand an UNNORM? + bne.b fu_op2_p # no + bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO + +fu_op2_p: + mov.b %d0,STAG(%a6) # save src optype tag + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # fetch rnd mode/prec + + lea FP_SRC(%a6),%a0 # pass ptr to src operand + + mov.l (%a6),EXC_A6(%a6) # in case a6 changes + bsr.l fout # call fmove out routine + +# Exceptions in order of precedence: +# BSUN : no +# SNAN : yes +# OPERR : if ((k_factor > +17) || (dec. exp exceeds 3 digits)) +# OVFL : no +# UNFL : no +# DZ : no +# INEX2 : yes +# INEX1 : no + +# determine the highest priority exception(if any) set by the +# emulation routine that has also been enabled by the user. + mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions enabled + bne.w fu_out_ena_p # some are enabled + +fu_out_exit_p: + mov.l EXC_A6(%a6),(%a6) # restore a6 + + btst &0x5,EXC_SR(%a6) # user or supervisor? + bne.b fu_out_exit_s_p # supervisor + + mov.l EXC_A7(%a6),%a0 # update user a7 + mov.l %a0,%usp + +fu_out_exit_cont_p: + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + unlk %a6 # unravel stack frame + + btst &0x7,(%sp) # is trace on? + bne.w fu_trace_p # yes + + bra.l _fpsp_done # exit to os + +# the exception occurred in supervisor mode. check to see if the +# addressing mode was -(a7). if so, we'll need to shift the +# stack frame "down". +fu_out_exit_s_p: + btst &mda7_bit,SPCOND_FLG(%a6) # was ea mode -(a7) + beq.b fu_out_exit_cont_p # no + + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + mov.l (%a6),%a6 # restore frame pointer + + mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp) + mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp) + +# now, copy the result to the proper place on the stack + mov.l LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp) + mov.l LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp) + mov.l LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp) + + add.l &LOCAL_SIZE-0x8,%sp + + btst &0x7,(%sp) + bne.w fu_trace_p + + bra.l _fpsp_done + +fu_out_ena_p: + and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enabled + bfffo %d0{&24:&8},%d0 # find highest priority exception + beq.w fu_out_exit_p + + mov.l EXC_A6(%a6),(%a6) # restore a6 + +# an exception occurred and that exception was enabled. +# the only exception possible on packed move out are INEX, OPERR, and SNAN. +fu_out_exc_p: + cmpi.b %d0,&0x1a + bgt.w fu_inex_p2 + beq.w fu_operr_p + +fu_snan_p: + btst &0x5,EXC_SR(%a6) + bne.b fu_snan_s_p + + mov.l EXC_A7(%a6),%a0 + mov.l %a0,%usp + bra.w fu_snan + +fu_snan_s_p: + cmpi.b SPCOND_FLG(%a6),&mda7_flg + bne.w fu_snan + +# the instruction was "fmove.p fpn,-(a7)" from supervisor mode. +# the strategy is to move the exception frame "down" 12 bytes. then, we +# can store the default result where the exception frame was. + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + mov.w &0x30d8,EXC_VOFF(%a6) # vector offset = 0xd0 + mov.w &0xe006,2+FP_SRC(%a6) # set fsave status + + frestore FP_SRC(%a6) # restore src operand + + mov.l (%a6),%a6 # restore frame pointer + + mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp) + mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp) + mov.l LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp) + +# now, we copy the default result to it's proper location + mov.l LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp) + mov.l LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp) + mov.l LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp) + + add.l &LOCAL_SIZE-0x8,%sp + + + bra.l _real_snan + +fu_operr_p: + btst &0x5,EXC_SR(%a6) + bne.w fu_operr_p_s + + mov.l EXC_A7(%a6),%a0 + mov.l %a0,%usp + bra.w fu_operr + +fu_operr_p_s: + cmpi.b SPCOND_FLG(%a6),&mda7_flg + bne.w fu_operr + +# the instruction was "fmove.p fpn,-(a7)" from supervisor mode. +# the strategy is to move the exception frame "down" 12 bytes. then, we +# can store the default result where the exception frame was. + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + mov.w &0x30d0,EXC_VOFF(%a6) # vector offset = 0xd0 + mov.w &0xe004,2+FP_SRC(%a6) # set fsave status + + frestore FP_SRC(%a6) # restore src operand + + mov.l (%a6),%a6 # restore frame pointer + + mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp) + mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp) + mov.l LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp) + +# now, we copy the default result to it's proper location + mov.l LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp) + mov.l LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp) + mov.l LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp) + + add.l &LOCAL_SIZE-0x8,%sp + + + bra.l _real_operr + +fu_inex_p2: + btst &0x5,EXC_SR(%a6) + bne.w fu_inex_s_p2 + + mov.l EXC_A7(%a6),%a0 + mov.l %a0,%usp + bra.w fu_inex + +fu_inex_s_p2: + cmpi.b SPCOND_FLG(%a6),&mda7_flg + bne.w fu_inex + +# the instruction was "fmove.p fpn,-(a7)" from supervisor mode. +# the strategy is to move the exception frame "down" 12 bytes. then, we +# can store the default result where the exception frame was. + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + mov.w &0x30c4,EXC_VOFF(%a6) # vector offset = 0xc4 + mov.w &0xe001,2+FP_SRC(%a6) # set fsave status + + frestore FP_SRC(%a6) # restore src operand + + mov.l (%a6),%a6 # restore frame pointer + + mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp) + mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp) + mov.l LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp) + +# now, we copy the default result to it's proper location + mov.l LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp) + mov.l LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp) + mov.l LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp) + + add.l &LOCAL_SIZE-0x8,%sp + + + bra.l _real_inex + +######################################################################### + +# +# if we're stuffing a source operand back into an fsave frame then we +# have to make sure that for single or double source operands that the +# format stuffed is as weird as the hardware usually makes it. +# + global funimp_skew +funimp_skew: + bfextu EXC_EXTWORD(%a6){&3:&3},%d0 # extract src specifier + cmpi.b %d0,&0x1 # was src sgl? + beq.b funimp_skew_sgl # yes + cmpi.b %d0,&0x5 # was src dbl? + beq.b funimp_skew_dbl # yes + rts + +funimp_skew_sgl: + mov.w FP_SRC_EX(%a6),%d0 # fetch DENORM exponent + andi.w &0x7fff,%d0 # strip sign + beq.b funimp_skew_sgl_not + cmpi.w %d0,&0x3f80 + bgt.b funimp_skew_sgl_not + neg.w %d0 # make exponent negative + addi.w &0x3f81,%d0 # find amt to shift + mov.l FP_SRC_HI(%a6),%d1 # fetch DENORM hi(man) + lsr.l %d0,%d1 # shift it + bset &31,%d1 # set j-bit + mov.l %d1,FP_SRC_HI(%a6) # insert new hi(man) + andi.w &0x8000,FP_SRC_EX(%a6) # clear old exponent + ori.w &0x3f80,FP_SRC_EX(%a6) # insert new "skewed" exponent +funimp_skew_sgl_not: + rts + +funimp_skew_dbl: + mov.w FP_SRC_EX(%a6),%d0 # fetch DENORM exponent + andi.w &0x7fff,%d0 # strip sign + beq.b funimp_skew_dbl_not + cmpi.w %d0,&0x3c00 + bgt.b funimp_skew_dbl_not + + tst.b FP_SRC_EX(%a6) # make "internal format" + smi.b 0x2+FP_SRC(%a6) + mov.w %d0,FP_SRC_EX(%a6) # insert exponent with cleared sign + clr.l %d0 # clear g,r,s + lea FP_SRC(%a6),%a0 # pass ptr to src op + mov.w &0x3c01,%d1 # pass denorm threshold + bsr.l dnrm_lp # denorm it + mov.w &0x3c00,%d0 # new exponent + tst.b 0x2+FP_SRC(%a6) # is sign set? + beq.b fss_dbl_denorm_done # no + bset &15,%d0 # set sign +fss_dbl_denorm_done: + bset &0x7,FP_SRC_HI(%a6) # set j-bit + mov.w %d0,FP_SRC_EX(%a6) # insert new exponent +funimp_skew_dbl_not: + rts + +######################################################################### + global _mem_write2 +_mem_write2: + btst &0x5,EXC_SR(%a6) + beq.l _dmem_write + mov.l 0x0(%a0),FP_DST_EX(%a6) + mov.l 0x4(%a0),FP_DST_HI(%a6) + mov.l 0x8(%a0),FP_DST_LO(%a6) + clr.l %d1 + rts + +######################################################################### +# XDEF **************************************************************** # +# _fpsp_effadd(): 060FPSP entry point for FP "Unimplemented # +# effective address" exception. # +# # +# This handler should be the first code executed upon taking the # +# FP Unimplemented Effective Address exception in an operating # +# system. # +# # +# XREF **************************************************************** # +# _imem_read_long() - read instruction longword # +# fix_skewed_ops() - adjust src operand in fsave frame # +# set_tag_x() - determine optype of src/dst operands # +# store_fpreg() - store opclass 0 or 2 result to FP regfile # +# unnorm_fix() - change UNNORM operands to NORM or ZERO # +# load_fpn2() - load dst operand from FP regfile # +# tbl_unsupp - add of table of emulation routines for opclass 0,2 # +# decbin() - convert packed data to FP binary data # +# _real_fpu_disabled() - "callout" for "FPU disabled" exception # +# _real_access() - "callout" for access error exception # +# _mem_read() - read extended immediate operand from memory # +# _fpsp_done() - "callout" for exit; work all done # +# _real_trace() - "callout" for Trace enabled exception # +# fmovm_dynamic() - emulate dynamic fmovm instruction # +# fmovm_ctrl() - emulate fmovm control instruction # +# # +# INPUT *************************************************************** # +# - The system stack contains the "Unimplemented " stk frame # +# # +# OUTPUT ************************************************************** # +# If access error: # +# - The system stack is changed to an access error stack frame # +# If FPU disabled: # +# - The system stack is changed to an FPU disabled stack frame # +# If Trace exception enabled: # +# - The system stack is changed to a Trace exception stack frame # +# Else: (normal case) # +# - None (correct result has been stored as appropriate) # +# # +# ALGORITHM *********************************************************** # +# This exception handles 3 types of operations: # +# (1) FP Instructions using extended precision or packed immediate # +# addressing mode. # +# (2) The "fmovm.x" instruction w/ dynamic register specification. # +# (3) The "fmovm.l" instruction w/ 2 or 3 control registers. # +# # +# For immediate data operations, the data is read in w/ a # +# _mem_read() "callout", converted to FP binary (if packed), and used # +# as the source operand to the instruction specified by the instruction # +# word. If no FP exception should be reported ads a result of the # +# emulation, then the result is stored to the destination register and # +# the handler exits through _fpsp_done(). If an enabled exc has been # +# signalled as a result of emulation, then an fsave state frame # +# corresponding to the FP exception type must be entered into the 060 # +# FPU before exiting. In either the enabled or disabled cases, we # +# must also check if a Trace exception is pending, in which case, we # +# must create a Trace exception stack frame from the current exception # +# stack frame. If no Trace is pending, we simply exit through # +# _fpsp_done(). # +# For "fmovm.x", call the routine fmovm_dynamic() which will # +# decode and emulate the instruction. No FP exceptions can be pending # +# as a result of this operation emulation. A Trace exception can be # +# pending, though, which means the current stack frame must be changed # +# to a Trace stack frame and an exit made through _real_trace(). # +# For the case of "fmovm.x Dn,-(a7)", where the offending instruction # +# was executed from supervisor mode, this handler must store the FP # +# register file values to the system stack by itself since # +# fmovm_dynamic() can't handle this. A normal exit is made through # +# fpsp_done(). # +# For "fmovm.l", fmovm_ctrl() is used to emulate the instruction. # +# Again, a Trace exception may be pending and an exit made through # +# _real_trace(). Else, a normal exit is made through _fpsp_done(). # +# # +# Before any of the above is attempted, it must be checked to # +# see if the FPU is disabled. Since the "Unimp " exception is taken # +# before the "FPU disabled" exception, but the "FPU disabled" exception # +# has higher priority, we check the disabled bit in the PCR. If set, # +# then we must create an 8 word "FPU disabled" exception stack frame # +# from the current 4 word exception stack frame. This includes # +# reproducing the effective address of the instruction to put on the # +# new stack frame. # +# # +# In the process of all emulation work, if a _mem_read() # +# "callout" returns a failing result indicating an access error, then # +# we must create an access error stack frame from the current stack # +# frame. This information includes a faulting address and a fault- # +# status-longword. These are created within this handler. # +# # +######################################################################### + + global _fpsp_effadd +_fpsp_effadd: + +# This exception type takes priority over the "Line F Emulator" +# exception. Therefore, the FPU could be disabled when entering here. +# So, we must check to see if it's disabled and handle that case separately. + mov.l %d0,-(%sp) # save d0 + movc %pcr,%d0 # load proc cr + btst &0x1,%d0 # is FPU disabled? + bne.w iea_disabled # yes + mov.l (%sp)+,%d0 # restore d0 + + link %a6,&-LOCAL_SIZE # init stack frame + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack + +# PC of instruction that took the exception is the PC in the frame + mov.l EXC_PC(%a6),EXC_EXTWPTR(%a6) + + mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr + addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr + bsr.l _imem_read_long # fetch the instruction words + mov.l %d0,EXC_OPWORD(%a6) # store OPWORD and EXTWORD + +######################################################################### + + tst.w %d0 # is operation fmovem? + bmi.w iea_fmovm # yes + +# +# here, we will have: +# fabs fdabs fsabs facos fmod +# fadd fdadd fsadd fasin frem +# fcmp fatan fscale +# fdiv fddiv fsdiv fatanh fsin +# fint fcos fsincos +# fintrz fcosh fsinh +# fmove fdmove fsmove fetox ftan +# fmul fdmul fsmul fetoxm1 ftanh +# fneg fdneg fsneg fgetexp ftentox +# fsgldiv fgetman ftwotox +# fsglmul flog10 +# fsqrt flog2 +# fsub fdsub fssub flogn +# ftst flognp1 +# which can all use f.{x,p} +# so, now it's immediate data extended precision AND PACKED FORMAT! +# +iea_op: + andi.l &0x00ff00ff,USER_FPSR(%a6) + + btst &0xa,%d0 # is src fmt x or p? + bne.b iea_op_pack # packed + + + mov.l EXC_EXTWPTR(%a6),%a0 # pass: ptr to # + lea FP_SRC(%a6),%a1 # pass: ptr to super addr + mov.l &0xc,%d0 # pass: 12 bytes + bsr.l _imem_read # read extended immediate + + tst.l %d1 # did ifetch fail? + bne.w iea_iacc # yes + + bra.b iea_op_setsrc + +iea_op_pack: + + mov.l EXC_EXTWPTR(%a6),%a0 # pass: ptr to # + lea FP_SRC(%a6),%a1 # pass: ptr to super dst + mov.l &0xc,%d0 # pass: 12 bytes + bsr.l _imem_read # read packed operand + + tst.l %d1 # did ifetch fail? + bne.w iea_iacc # yes + +# The packed operand is an INF or a NAN if the exponent field is all ones. + bfextu FP_SRC(%a6){&1:&15},%d0 # get exp + cmpi.w %d0,&0x7fff # INF or NAN? + beq.b iea_op_setsrc # operand is an INF or NAN + +# The packed operand is a zero if the mantissa is all zero, else it's +# a normal packed op. + mov.b 3+FP_SRC(%a6),%d0 # get byte 4 + andi.b &0x0f,%d0 # clear all but last nybble + bne.b iea_op_gp_not_spec # not a zero + tst.l FP_SRC_HI(%a6) # is lw 2 zero? + bne.b iea_op_gp_not_spec # not a zero + tst.l FP_SRC_LO(%a6) # is lw 3 zero? + beq.b iea_op_setsrc # operand is a ZERO +iea_op_gp_not_spec: + lea FP_SRC(%a6),%a0 # pass: ptr to packed op + bsr.l decbin # convert to extended + fmovm.x &0x80,FP_SRC(%a6) # make this the srcop + +iea_op_setsrc: + addi.l &0xc,EXC_EXTWPTR(%a6) # update extension word pointer + +# FP_SRC now holds the src operand. + lea FP_SRC(%a6),%a0 # pass: ptr to src op + bsr.l set_tag_x # tag the operand type + mov.b %d0,STAG(%a6) # could be ANYTHING!!! + cmpi.b %d0,&UNNORM # is operand an UNNORM? + bne.b iea_op_getdst # no + bsr.l unnorm_fix # yes; convert to NORM/DENORM/ZERO + mov.b %d0,STAG(%a6) # set new optype tag +iea_op_getdst: + clr.b STORE_FLG(%a6) # clear "store result" boolean + + btst &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic? + beq.b iea_op_extract # monadic + btst &0x4,1+EXC_CMDREG(%a6) # is operation fsincos,ftst,fcmp? + bne.b iea_op_spec # yes + +iea_op_loaddst: + bfextu EXC_CMDREG(%a6){&6:&3},%d0 # fetch dst regno + bsr.l load_fpn2 # load dst operand + + lea FP_DST(%a6),%a0 # pass: ptr to dst op + bsr.l set_tag_x # tag the operand type + mov.b %d0,DTAG(%a6) # could be ANYTHING!!! + cmpi.b %d0,&UNNORM # is operand an UNNORM? + bne.b iea_op_extract # no + bsr.l unnorm_fix # yes; convert to NORM/DENORM/ZERO + mov.b %d0,DTAG(%a6) # set new optype tag + bra.b iea_op_extract + +# the operation is fsincos, ftst, or fcmp. only fcmp is dyadic +iea_op_spec: + btst &0x3,1+EXC_CMDREG(%a6) # is operation fsincos? + beq.b iea_op_extract # yes +# now, we're left with ftst and fcmp. so, first let's tag them so that they don't +# store a result. then, only fcmp will branch back and pick up a dst operand. + st STORE_FLG(%a6) # don't store a final result + btst &0x1,1+EXC_CMDREG(%a6) # is operation fcmp? + beq.b iea_op_loaddst # yes + +iea_op_extract: + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass: rnd mode,prec + + mov.b 1+EXC_CMDREG(%a6),%d1 + andi.w &0x007f,%d1 # extract extension + + fmov.l &0x0,%fpcr + fmov.l &0x0,%fpsr + + lea FP_SRC(%a6),%a0 + lea FP_DST(%a6),%a1 + + mov.l (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr + jsr (tbl_unsupp.l,%pc,%d1.l*1) + +# +# Exceptions in order of precedence: +# BSUN : none +# SNAN : all operations +# OPERR : all reg-reg or mem-reg operations that can normally operr +# OVFL : same as OPERR +# UNFL : same as OPERR +# DZ : same as OPERR +# INEX2 : same as OPERR +# INEX1 : all packed immediate operations +# + +# we determine the highest priority exception(if any) set by the +# emulation routine that has also been enabled by the user. + mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions enabled + bne.b iea_op_ena # some are enabled + +# now, we save the result, unless, of course, the operation was ftst or fcmp. +# these don't save results. +iea_op_save: + tst.b STORE_FLG(%a6) # does this op store a result? + bne.b iea_op_exit1 # exit with no frestore + +iea_op_store: + bfextu EXC_CMDREG(%a6){&6:&3},%d0 # fetch dst regno + bsr.l store_fpreg # store the result + +iea_op_exit1: + mov.l EXC_PC(%a6),USER_FPIAR(%a6) # set FPIAR to "Current PC" + mov.l EXC_EXTWPTR(%a6),EXC_PC(%a6) # set "Next PC" in exc frame + + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + unlk %a6 # unravel the frame + + btst &0x7,(%sp) # is trace on? + bne.w iea_op_trace # yes + + bra.l _fpsp_done # exit to os + +iea_op_ena: + and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enable and set + bfffo %d0{&24:&8},%d0 # find highest priority exception + bne.b iea_op_exc # at least one was set + +# no exception occurred. now, did a disabled, exact overflow occur with inexact +# enabled? if so, then we have to stuff an overflow frame into the FPU. + btst &ovfl_bit,FPSR_EXCEPT(%a6) # did overflow occur? + beq.b iea_op_save + +iea_op_ovfl: + btst &inex2_bit,FPCR_ENABLE(%a6) # is inexact enabled? + beq.b iea_op_store # no + bra.b iea_op_exc_ovfl # yes + +# an enabled exception occurred. we have to insert the exception type back into +# the machine. +iea_op_exc: + subi.l &24,%d0 # fix offset to be 0-8 + cmpi.b %d0,&0x6 # is exception INEX? + bne.b iea_op_exc_force # no + +# the enabled exception was inexact. so, if it occurs with an overflow +# or underflow that was disabled, then we have to force an overflow or +# underflow frame. + btst &ovfl_bit,FPSR_EXCEPT(%a6) # did overflow occur? + bne.b iea_op_exc_ovfl # yes + btst &unfl_bit,FPSR_EXCEPT(%a6) # did underflow occur? + bne.b iea_op_exc_unfl # yes + +iea_op_exc_force: + mov.w (tbl_iea_except.b,%pc,%d0.w*2),2+FP_SRC(%a6) + bra.b iea_op_exit2 # exit with frestore + +tbl_iea_except: + short 0xe002, 0xe006, 0xe004, 0xe005 + short 0xe003, 0xe002, 0xe001, 0xe001 + +iea_op_exc_ovfl: + mov.w &0xe005,2+FP_SRC(%a6) + bra.b iea_op_exit2 + +iea_op_exc_unfl: + mov.w &0xe003,2+FP_SRC(%a6) + +iea_op_exit2: + mov.l EXC_PC(%a6),USER_FPIAR(%a6) # set FPIAR to "Current PC" + mov.l EXC_EXTWPTR(%a6),EXC_PC(%a6) # set "Next PC" in exc frame + + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + frestore FP_SRC(%a6) # restore exceptional state + + unlk %a6 # unravel the frame + + btst &0x7,(%sp) # is trace on? + bne.b iea_op_trace # yes + + bra.l _fpsp_done # exit to os + +# +# The opclass two instruction that took an "Unimplemented Effective Address" +# exception was being traced. Make the "current" PC the FPIAR and put it in +# the trace stack frame then jump to _real_trace(). +# +# UNIMP EA FRAME TRACE FRAME +# ***************** ***************** +# * 0x0 * 0x0f0 * * Current * +# ***************** * PC * +# * Current * ***************** +# * PC * * 0x2 * 0x024 * +# ***************** ***************** +# * SR * * Next * +# ***************** * PC * +# ***************** +# * SR * +# ***************** +iea_op_trace: + mov.l (%sp),-(%sp) # shift stack frame "down" + mov.w 0x8(%sp),0x4(%sp) + mov.w &0x2024,0x6(%sp) # stk fmt = 0x2; voff = 0x024 + fmov.l %fpiar,0x8(%sp) # "Current PC" is in FPIAR + + bra.l _real_trace + +######################################################################### +iea_fmovm: + btst &14,%d0 # ctrl or data reg + beq.w iea_fmovm_ctrl + +iea_fmovm_data: + + btst &0x5,EXC_SR(%a6) # user or supervisor mode + bne.b iea_fmovm_data_s + +iea_fmovm_data_u: + mov.l %usp,%a0 + mov.l %a0,EXC_A7(%a6) # store current a7 + bsr.l fmovm_dynamic # do dynamic fmovm + mov.l EXC_A7(%a6),%a0 # load possibly new a7 + mov.l %a0,%usp # update usp + bra.w iea_fmovm_exit + +iea_fmovm_data_s: + clr.b SPCOND_FLG(%a6) + lea 0x2+EXC_VOFF(%a6),%a0 + mov.l %a0,EXC_A7(%a6) + bsr.l fmovm_dynamic # do dynamic fmovm + + cmpi.b SPCOND_FLG(%a6),&mda7_flg + beq.w iea_fmovm_data_predec + cmpi.b SPCOND_FLG(%a6),&mia7_flg + bne.w iea_fmovm_exit + +# right now, d0 = the size. +# the data has been fetched from the supervisor stack, but we have not +# incremented the stack pointer by the appropriate number of bytes. +# do it here. +iea_fmovm_data_postinc: + btst &0x7,EXC_SR(%a6) + bne.b iea_fmovm_data_pi_trace + + mov.w EXC_SR(%a6),(EXC_SR,%a6,%d0) + mov.l EXC_EXTWPTR(%a6),(EXC_PC,%a6,%d0) + mov.w &0x00f0,(EXC_VOFF,%a6,%d0) + + lea (EXC_SR,%a6,%d0),%a0 + mov.l %a0,EXC_SR(%a6) + + fmovm.x EXC_FP0(%a6),&0xc0 # restore fp0-fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + unlk %a6 + mov.l (%sp)+,%sp + bra.l _fpsp_done + +iea_fmovm_data_pi_trace: + mov.w EXC_SR(%a6),(EXC_SR-0x4,%a6,%d0) + mov.l EXC_EXTWPTR(%a6),(EXC_PC-0x4,%a6,%d0) + mov.w &0x2024,(EXC_VOFF-0x4,%a6,%d0) + mov.l EXC_PC(%a6),(EXC_VOFF+0x2-0x4,%a6,%d0) + + lea (EXC_SR-0x4,%a6,%d0),%a0 + mov.l %a0,EXC_SR(%a6) + + fmovm.x EXC_FP0(%a6),&0xc0 # restore fp0-fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + unlk %a6 + mov.l (%sp)+,%sp + bra.l _real_trace + +# right now, d1 = size and d0 = the strg. +iea_fmovm_data_predec: + mov.b %d1,EXC_VOFF(%a6) # store strg + mov.b %d0,0x1+EXC_VOFF(%a6) # store size + + fmovm.x EXC_FP0(%a6),&0xc0 # restore fp0-fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + mov.l (%a6),-(%sp) # make a copy of a6 + mov.l %d0,-(%sp) # save d0 + mov.l %d1,-(%sp) # save d1 + mov.l EXC_EXTWPTR(%a6),-(%sp) # make a copy of Next PC + + clr.l %d0 + mov.b 0x1+EXC_VOFF(%a6),%d0 # fetch size + neg.l %d0 # get negative of size + + btst &0x7,EXC_SR(%a6) # is trace enabled? + beq.b iea_fmovm_data_p2 + + mov.w EXC_SR(%a6),(EXC_SR-0x4,%a6,%d0) + mov.l EXC_PC(%a6),(EXC_VOFF-0x2,%a6,%d0) + mov.l (%sp)+,(EXC_PC-0x4,%a6,%d0) + mov.w &0x2024,(EXC_VOFF-0x4,%a6,%d0) + + pea (%a6,%d0) # create final sp + bra.b iea_fmovm_data_p3 + +iea_fmovm_data_p2: + mov.w EXC_SR(%a6),(EXC_SR,%a6,%d0) + mov.l (%sp)+,(EXC_PC,%a6,%d0) + mov.w &0x00f0,(EXC_VOFF,%a6,%d0) + + pea (0x4,%a6,%d0) # create final sp + +iea_fmovm_data_p3: + clr.l %d1 + mov.b EXC_VOFF(%a6),%d1 # fetch strg + + tst.b %d1 + bpl.b fm_1 + fmovm.x &0x80,(0x4+0x8,%a6,%d0) + addi.l &0xc,%d0 +fm_1: + lsl.b &0x1,%d1 + bpl.b fm_2 + fmovm.x &0x40,(0x4+0x8,%a6,%d0) + addi.l &0xc,%d0 +fm_2: + lsl.b &0x1,%d1 + bpl.b fm_3 + fmovm.x &0x20,(0x4+0x8,%a6,%d0) + addi.l &0xc,%d0 +fm_3: + lsl.b &0x1,%d1 + bpl.b fm_4 + fmovm.x &0x10,(0x4+0x8,%a6,%d0) + addi.l &0xc,%d0 +fm_4: + lsl.b &0x1,%d1 + bpl.b fm_5 + fmovm.x &0x08,(0x4+0x8,%a6,%d0) + addi.l &0xc,%d0 +fm_5: + lsl.b &0x1,%d1 + bpl.b fm_6 + fmovm.x &0x04,(0x4+0x8,%a6,%d0) + addi.l &0xc,%d0 +fm_6: + lsl.b &0x1,%d1 + bpl.b fm_7 + fmovm.x &0x02,(0x4+0x8,%a6,%d0) + addi.l &0xc,%d0 +fm_7: + lsl.b &0x1,%d1 + bpl.b fm_end + fmovm.x &0x01,(0x4+0x8,%a6,%d0) +fm_end: + mov.l 0x4(%sp),%d1 + mov.l 0x8(%sp),%d0 + mov.l 0xc(%sp),%a6 + mov.l (%sp)+,%sp + + btst &0x7,(%sp) # is trace enabled? + beq.l _fpsp_done + bra.l _real_trace + +######################################################################### +iea_fmovm_ctrl: + + bsr.l fmovm_ctrl # load ctrl regs + +iea_fmovm_exit: + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + btst &0x7,EXC_SR(%a6) # is trace on? + bne.b iea_fmovm_trace # yes + + mov.l EXC_EXTWPTR(%a6),EXC_PC(%a6) # set Next PC + + unlk %a6 # unravel the frame + + bra.l _fpsp_done # exit to os + +# +# The control reg instruction that took an "Unimplemented Effective Address" +# exception was being traced. The "Current PC" for the trace frame is the +# PC stacked for Unimp EA. The "Next PC" is in EXC_EXTWPTR. +# After fixing the stack frame, jump to _real_trace(). +# +# UNIMP EA FRAME TRACE FRAME +# ***************** ***************** +# * 0x0 * 0x0f0 * * Current * +# ***************** * PC * +# * Current * ***************** +# * PC * * 0x2 * 0x024 * +# ***************** ***************** +# * SR * * Next * +# ***************** * PC * +# ***************** +# * SR * +# ***************** +# this ain't a pretty solution, but it works: +# -restore a6 (not with unlk) +# -shift stack frame down over where old a6 used to be +# -add LOCAL_SIZE to stack pointer +iea_fmovm_trace: + mov.l (%a6),%a6 # restore frame pointer + mov.w EXC_SR+LOCAL_SIZE(%sp),0x0+LOCAL_SIZE(%sp) + mov.l EXC_PC+LOCAL_SIZE(%sp),0x8+LOCAL_SIZE(%sp) + mov.l EXC_EXTWPTR+LOCAL_SIZE(%sp),0x2+LOCAL_SIZE(%sp) + mov.w &0x2024,0x6+LOCAL_SIZE(%sp) # stk fmt = 0x2; voff = 0x024 + add.l &LOCAL_SIZE,%sp # clear stack frame + + bra.l _real_trace + +######################################################################### +# The FPU is disabled and so we should really have taken the "Line +# F Emulator" exception. So, here we create an 8-word stack frame +# from our 4-word stack frame. This means we must calculate the length +# the the faulting instruction to get the "next PC". This is trivial for +# immediate operands but requires some extra work for fmovm dynamic +# which can use most addressing modes. +iea_disabled: + mov.l (%sp)+,%d0 # restore d0 + + link %a6,&-LOCAL_SIZE # init stack frame + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + +# PC of instruction that took the exception is the PC in the frame + mov.l EXC_PC(%a6),EXC_EXTWPTR(%a6) + mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr + addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr + bsr.l _imem_read_long # fetch the instruction words + mov.l %d0,EXC_OPWORD(%a6) # store OPWORD and EXTWORD + + tst.w %d0 # is instr fmovm? + bmi.b iea_dis_fmovm # yes +# instruction is using an extended precision immediate operand. therefore, +# the total instruction length is 16 bytes. +iea_dis_immed: + mov.l &0x10,%d0 # 16 bytes of instruction + bra.b iea_dis_cont +iea_dis_fmovm: + btst &0xe,%d0 # is instr fmovm ctrl + bne.b iea_dis_fmovm_data # no +# the instruction is a fmovm.l with 2 or 3 registers. + bfextu %d0{&19:&3},%d1 + mov.l &0xc,%d0 + cmpi.b %d1,&0x7 # move all regs? + bne.b iea_dis_cont + addq.l &0x4,%d0 + bra.b iea_dis_cont +# the instruction is an fmovm.x dynamic which can use many addressing +# modes and thus can have several different total instruction lengths. +# call fmovm_calc_ea which will go through the ea calc process and, +# as a by-product, will tell us how long the instruction is. +iea_dis_fmovm_data: + clr.l %d0 + bsr.l fmovm_calc_ea + mov.l EXC_EXTWPTR(%a6),%d0 + sub.l EXC_PC(%a6),%d0 +iea_dis_cont: + mov.w %d0,EXC_VOFF(%a6) # store stack shift value + + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + unlk %a6 + +# here, we actually create the 8-word frame from the 4-word frame, +# with the "next PC" as additional info. +# the field is let as undefined. + subq.l &0x8,%sp # make room for new stack + mov.l %d0,-(%sp) # save d0 + mov.w 0xc(%sp),0x4(%sp) # move SR + mov.l 0xe(%sp),0x6(%sp) # move Current PC + clr.l %d0 + mov.w 0x12(%sp),%d0 + mov.l 0x6(%sp),0x10(%sp) # move Current PC + add.l %d0,0x6(%sp) # make Next PC + mov.w &0x402c,0xa(%sp) # insert offset,frame format + mov.l (%sp)+,%d0 # restore d0 + + bra.l _real_fpu_disabled + +########## + +iea_iacc: + movc %pcr,%d0 + btst &0x1,%d0 + bne.b iea_iacc_cont + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 on stack +iea_iacc_cont: + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + unlk %a6 + + subq.w &0x8,%sp # make stack frame bigger + mov.l 0x8(%sp),(%sp) # store SR,hi(PC) + mov.w 0xc(%sp),0x4(%sp) # store lo(PC) + mov.w &0x4008,0x6(%sp) # store voff + mov.l 0x2(%sp),0x8(%sp) # store ea + mov.l &0x09428001,0xc(%sp) # store fslw + +iea_acc_done: + btst &0x5,(%sp) # user or supervisor mode? + beq.b iea_acc_done2 # user + bset &0x2,0xd(%sp) # set supervisor TM bit + +iea_acc_done2: + bra.l _real_access + +iea_dacc: + lea -LOCAL_SIZE(%a6),%sp + + movc %pcr,%d1 + btst &0x1,%d1 + bne.b iea_dacc_cont + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 on stack + fmovm.l LOCAL_SIZE+USER_FPCR(%sp),%fpcr,%fpsr,%fpiar # restore ctrl regs +iea_dacc_cont: + mov.l (%a6),%a6 + + mov.l 0x4+LOCAL_SIZE(%sp),-0x8+0x4+LOCAL_SIZE(%sp) + mov.w 0x8+LOCAL_SIZE(%sp),-0x8+0x8+LOCAL_SIZE(%sp) + mov.w &0x4008,-0x8+0xa+LOCAL_SIZE(%sp) + mov.l %a0,-0x8+0xc+LOCAL_SIZE(%sp) + mov.w %d0,-0x8+0x10+LOCAL_SIZE(%sp) + mov.w &0x0001,-0x8+0x12+LOCAL_SIZE(%sp) + + movm.l LOCAL_SIZE+EXC_DREGS(%sp),&0x0303 # restore d0-d1/a0-a1 + add.w &LOCAL_SIZE-0x4,%sp + + bra.b iea_acc_done + +######################################################################### +# XDEF **************************************************************** # +# _fpsp_operr(): 060FPSP entry point for FP Operr exception. # +# # +# This handler should be the first code executed upon taking the # +# FP Operand Error exception in an operating system. # +# # +# XREF **************************************************************** # +# _imem_read_long() - read instruction longword # +# fix_skewed_ops() - adjust src operand in fsave frame # +# _real_operr() - "callout" to operating system operr handler # +# _dmem_write_{byte,word,long}() - store data to mem (opclass 3) # +# store_dreg_{b,w,l}() - store data to data regfile (opclass 3) # +# facc_out_{b,w,l}() - store to memory took access error (opcl 3) # +# # +# INPUT *************************************************************** # +# - The system stack contains the FP Operr exception frame # +# - The fsave frame contains the source operand # +# # +# OUTPUT ************************************************************** # +# No access error: # +# - The system stack is unchanged # +# - The fsave frame contains the adjusted src op for opclass 0,2 # +# # +# ALGORITHM *********************************************************** # +# In a system where the FP Operr exception is enabled, the goal # +# is to get to the handler specified at _real_operr(). But, on the 060, # +# for opclass zero and two instruction taking this exception, the # +# input operand in the fsave frame may be incorrect for some cases # +# and needs to be corrected. This handler calls fix_skewed_ops() to # +# do just this and then exits through _real_operr(). # +# For opclass 3 instructions, the 060 doesn't store the default # +# operr result out to memory or data register file as it should. # +# This code must emulate the move out before finally exiting through # +# _real_inex(). The move out, if to memory, is performed using # +# _mem_write() "callout" routines that may return a failing result. # +# In this special case, the handler must exit through facc_out() # +# which creates an access error stack frame from the current operr # +# stack frame. # +# # +######################################################################### + + global _fpsp_operr +_fpsp_operr: + + link.w %a6,&-LOCAL_SIZE # init stack frame + + fsave FP_SRC(%a6) # grab the "busy" frame + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack + +# the FPIAR holds the "current PC" of the faulting instruction + mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6) + + mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr + addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr + bsr.l _imem_read_long # fetch the instruction words + mov.l %d0,EXC_OPWORD(%a6) + +############################################################################## + + btst &13,%d0 # is instr an fmove out? + bne.b foperr_out # fmove out + + +# here, we simply see if the operand in the fsave frame needs to be "unskewed". +# this would be the case for opclass two operations with a source infinity or +# denorm operand in the sgl or dbl format. NANs also become skewed, but can't +# cause an operr so we don't need to check for them here. + lea FP_SRC(%a6),%a0 # pass: ptr to src op + bsr.l fix_skewed_ops # fix src op + +foperr_exit: + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + frestore FP_SRC(%a6) + + unlk %a6 + bra.l _real_operr + +######################################################################## + +# +# the hardware does not save the default result to memory on enabled +# operand error exceptions. we do this here before passing control to +# the user operand error handler. +# +# byte, word, and long destination format operations can pass +# through here. we simply need to test the sign of the src +# operand and save the appropriate minimum or maximum integer value +# to the effective address as pointed to by the stacked effective address. +# +# although packed opclass three operations can take operand error +# exceptions, they won't pass through here since they are caught +# first by the unsupported data format exception handler. that handler +# sends them directly to _real_operr() if necessary. +# +foperr_out: + + mov.w FP_SRC_EX(%a6),%d1 # fetch exponent + andi.w &0x7fff,%d1 + cmpi.w %d1,&0x7fff + bne.b foperr_out_not_qnan +# the operand is either an infinity or a QNAN. + tst.l FP_SRC_LO(%a6) + bne.b foperr_out_qnan + mov.l FP_SRC_HI(%a6),%d1 + andi.l &0x7fffffff,%d1 + beq.b foperr_out_not_qnan +foperr_out_qnan: + mov.l FP_SRC_HI(%a6),L_SCR1(%a6) + bra.b foperr_out_jmp + +foperr_out_not_qnan: + mov.l &0x7fffffff,%d1 + tst.b FP_SRC_EX(%a6) + bpl.b foperr_out_not_qnan2 + addq.l &0x1,%d1 +foperr_out_not_qnan2: + mov.l %d1,L_SCR1(%a6) + +foperr_out_jmp: + bfextu %d0{&19:&3},%d0 # extract dst format field + mov.b 1+EXC_OPWORD(%a6),%d1 # extract mode,reg + mov.w (tbl_operr.b,%pc,%d0.w*2),%a0 + jmp (tbl_operr.b,%pc,%a0) + +tbl_operr: + short foperr_out_l - tbl_operr # long word integer + short tbl_operr - tbl_operr # sgl prec shouldn't happen + short tbl_operr - tbl_operr # ext prec shouldn't happen + short foperr_exit - tbl_operr # packed won't enter here + short foperr_out_w - tbl_operr # word integer + short tbl_operr - tbl_operr # dbl prec shouldn't happen + short foperr_out_b - tbl_operr # byte integer + short tbl_operr - tbl_operr # packed won't enter here + +foperr_out_b: + mov.b L_SCR1(%a6),%d0 # load positive default result + cmpi.b %d1,&0x7 # is mode a data reg? + ble.b foperr_out_b_save_dn # yes + mov.l EXC_EA(%a6),%a0 # pass: of default result + bsr.l _dmem_write_byte # write the default result + + tst.l %d1 # did dstore fail? + bne.l facc_out_b # yes + + bra.w foperr_exit +foperr_out_b_save_dn: + andi.w &0x0007,%d1 + bsr.l store_dreg_b # store result to regfile + bra.w foperr_exit + +foperr_out_w: + mov.w L_SCR1(%a6),%d0 # load positive default result + cmpi.b %d1,&0x7 # is mode a data reg? + ble.b foperr_out_w_save_dn # yes + mov.l EXC_EA(%a6),%a0 # pass: of default result + bsr.l _dmem_write_word # write the default result + + tst.l %d1 # did dstore fail? + bne.l facc_out_w # yes + + bra.w foperr_exit +foperr_out_w_save_dn: + andi.w &0x0007,%d1 + bsr.l store_dreg_w # store result to regfile + bra.w foperr_exit + +foperr_out_l: + mov.l L_SCR1(%a6),%d0 # load positive default result + cmpi.b %d1,&0x7 # is mode a data reg? + ble.b foperr_out_l_save_dn # yes + mov.l EXC_EA(%a6),%a0 # pass: of default result + bsr.l _dmem_write_long # write the default result + + tst.l %d1 # did dstore fail? + bne.l facc_out_l # yes + + bra.w foperr_exit +foperr_out_l_save_dn: + andi.w &0x0007,%d1 + bsr.l store_dreg_l # store result to regfile + bra.w foperr_exit + +######################################################################### +# XDEF **************************************************************** # +# _fpsp_snan(): 060FPSP entry point for FP SNAN exception. # +# # +# This handler should be the first code executed upon taking the # +# FP Signalling NAN exception in an operating system. # +# # +# XREF **************************************************************** # +# _imem_read_long() - read instruction longword # +# fix_skewed_ops() - adjust src operand in fsave frame # +# _real_snan() - "callout" to operating system SNAN handler # +# _dmem_write_{byte,word,long}() - store data to mem (opclass 3) # +# store_dreg_{b,w,l}() - store data to data regfile (opclass 3) # +# facc_out_{b,w,l,d,x}() - store to mem took acc error (opcl 3) # +# _calc_ea_fout() - fix An if is -() or ()+; also get # +# # +# INPUT *************************************************************** # +# - The system stack contains the FP SNAN exception frame # +# - The fsave frame contains the source operand # +# # +# OUTPUT ************************************************************** # +# No access error: # +# - The system stack is unchanged # +# - The fsave frame contains the adjusted src op for opclass 0,2 # +# # +# ALGORITHM *********************************************************** # +# In a system where the FP SNAN exception is enabled, the goal # +# is to get to the handler specified at _real_snan(). But, on the 060, # +# for opclass zero and two instructions taking this exception, the # +# input operand in the fsave frame may be incorrect for some cases # +# and needs to be corrected. This handler calls fix_skewed_ops() to # +# do just this and then exits through _real_snan(). # +# For opclass 3 instructions, the 060 doesn't store the default # +# SNAN result out to memory or data register file as it should. # +# This code must emulate the move out before finally exiting through # +# _real_snan(). The move out, if to memory, is performed using # +# _mem_write() "callout" routines that may return a failing result. # +# In this special case, the handler must exit through facc_out() # +# which creates an access error stack frame from the current SNAN # +# stack frame. # +# For the case of an extended precision opclass 3 instruction, # +# if the effective addressing mode was -() or ()+, then the address # +# register must get updated by calling _calc_ea_fout(). If the # +# was -(a7) from supervisor mode, then the exception frame currently # +# on the system stack must be carefully moved "down" to make room # +# for the operand being moved. # +# # +######################################################################### + + global _fpsp_snan +_fpsp_snan: + + link.w %a6,&-LOCAL_SIZE # init stack frame + + fsave FP_SRC(%a6) # grab the "busy" frame + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack + +# the FPIAR holds the "current PC" of the faulting instruction + mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6) + + mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr + addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr + bsr.l _imem_read_long # fetch the instruction words + mov.l %d0,EXC_OPWORD(%a6) + +############################################################################## + + btst &13,%d0 # is instr an fmove out? + bne.w fsnan_out # fmove out + + +# here, we simply see if the operand in the fsave frame needs to be "unskewed". +# this would be the case for opclass two operations with a source infinity or +# denorm operand in the sgl or dbl format. NANs also become skewed and must be +# fixed here. + lea FP_SRC(%a6),%a0 # pass: ptr to src op + bsr.l fix_skewed_ops # fix src op + +fsnan_exit: + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + frestore FP_SRC(%a6) + + unlk %a6 + bra.l _real_snan + +######################################################################## + +# +# the hardware does not save the default result to memory on enabled +# snan exceptions. we do this here before passing control to +# the user snan handler. +# +# byte, word, long, and packed destination format operations can pass +# through here. since packed format operations already were handled by +# fpsp_unsupp(), then we need to do nothing else for them here. +# for byte, word, and long, we simply need to test the sign of the src +# operand and save the appropriate minimum or maximum integer value +# to the effective address as pointed to by the stacked effective address. +# +fsnan_out: + + bfextu %d0{&19:&3},%d0 # extract dst format field + mov.b 1+EXC_OPWORD(%a6),%d1 # extract mode,reg + mov.w (tbl_snan.b,%pc,%d0.w*2),%a0 + jmp (tbl_snan.b,%pc,%a0) + +tbl_snan: + short fsnan_out_l - tbl_snan # long word integer + short fsnan_out_s - tbl_snan # sgl prec shouldn't happen + short fsnan_out_x - tbl_snan # ext prec shouldn't happen + short tbl_snan - tbl_snan # packed needs no help + short fsnan_out_w - tbl_snan # word integer + short fsnan_out_d - tbl_snan # dbl prec shouldn't happen + short fsnan_out_b - tbl_snan # byte integer + short tbl_snan - tbl_snan # packed needs no help + +fsnan_out_b: + mov.b FP_SRC_HI(%a6),%d0 # load upper byte of SNAN + bset &6,%d0 # set SNAN bit + cmpi.b %d1,&0x7 # is mode a data reg? + ble.b fsnan_out_b_dn # yes + mov.l EXC_EA(%a6),%a0 # pass: of default result + bsr.l _dmem_write_byte # write the default result + + tst.l %d1 # did dstore fail? + bne.l facc_out_b # yes + + bra.w fsnan_exit +fsnan_out_b_dn: + andi.w &0x0007,%d1 + bsr.l store_dreg_b # store result to regfile + bra.w fsnan_exit + +fsnan_out_w: + mov.w FP_SRC_HI(%a6),%d0 # load upper word of SNAN + bset &14,%d0 # set SNAN bit + cmpi.b %d1,&0x7 # is mode a data reg? + ble.b fsnan_out_w_dn # yes + mov.l EXC_EA(%a6),%a0 # pass: of default result + bsr.l _dmem_write_word # write the default result + + tst.l %d1 # did dstore fail? + bne.l facc_out_w # yes + + bra.w fsnan_exit +fsnan_out_w_dn: + andi.w &0x0007,%d1 + bsr.l store_dreg_w # store result to regfile + bra.w fsnan_exit + +fsnan_out_l: + mov.l FP_SRC_HI(%a6),%d0 # load upper longword of SNAN + bset &30,%d0 # set SNAN bit + cmpi.b %d1,&0x7 # is mode a data reg? + ble.b fsnan_out_l_dn # yes + mov.l EXC_EA(%a6),%a0 # pass: of default result + bsr.l _dmem_write_long # write the default result + + tst.l %d1 # did dstore fail? + bne.l facc_out_l # yes + + bra.w fsnan_exit +fsnan_out_l_dn: + andi.w &0x0007,%d1 + bsr.l store_dreg_l # store result to regfile + bra.w fsnan_exit + +fsnan_out_s: + cmpi.b %d1,&0x7 # is mode a data reg? + ble.b fsnan_out_d_dn # yes + mov.l FP_SRC_EX(%a6),%d0 # fetch SNAN sign + andi.l &0x80000000,%d0 # keep sign + ori.l &0x7fc00000,%d0 # insert new exponent,SNAN bit + mov.l FP_SRC_HI(%a6),%d1 # load mantissa + lsr.l &0x8,%d1 # shift mantissa for sgl + or.l %d1,%d0 # create sgl SNAN + mov.l EXC_EA(%a6),%a0 # pass: of default result + bsr.l _dmem_write_long # write the default result + + tst.l %d1 # did dstore fail? + bne.l facc_out_l # yes + + bra.w fsnan_exit +fsnan_out_d_dn: + mov.l FP_SRC_EX(%a6),%d0 # fetch SNAN sign + andi.l &0x80000000,%d0 # keep sign + ori.l &0x7fc00000,%d0 # insert new exponent,SNAN bit + mov.l %d1,-(%sp) + mov.l FP_SRC_HI(%a6),%d1 # load mantissa + lsr.l &0x8,%d1 # shift mantissa for sgl + or.l %d1,%d0 # create sgl SNAN + mov.l (%sp)+,%d1 + andi.w &0x0007,%d1 + bsr.l store_dreg_l # store result to regfile + bra.w fsnan_exit + +fsnan_out_d: + mov.l FP_SRC_EX(%a6),%d0 # fetch SNAN sign + andi.l &0x80000000,%d0 # keep sign + ori.l &0x7ff80000,%d0 # insert new exponent,SNAN bit + mov.l FP_SRC_HI(%a6),%d1 # load hi mantissa + mov.l %d0,FP_SCR0_EX(%a6) # store to temp space + mov.l &11,%d0 # load shift amt + lsr.l %d0,%d1 + or.l %d1,FP_SCR0_EX(%a6) # create dbl hi + mov.l FP_SRC_HI(%a6),%d1 # load hi mantissa + andi.l &0x000007ff,%d1 + ror.l %d0,%d1 + mov.l %d1,FP_SCR0_HI(%a6) # store to temp space + mov.l FP_SRC_LO(%a6),%d1 # load lo mantissa + lsr.l %d0,%d1 + or.l %d1,FP_SCR0_HI(%a6) # create dbl lo + lea FP_SCR0(%a6),%a0 # pass: ptr to operand + mov.l EXC_EA(%a6),%a1 # pass: dst addr + movq.l &0x8,%d0 # pass: size of 8 bytes + bsr.l _dmem_write # write the default result + + tst.l %d1 # did dstore fail? + bne.l facc_out_d # yes + + bra.w fsnan_exit + +# for extended precision, if the addressing mode is pre-decrement or +# post-increment, then the address register did not get updated. +# in addition, for pre-decrement, the stacked is incorrect. +fsnan_out_x: + clr.b SPCOND_FLG(%a6) # clear special case flag + + mov.w FP_SRC_EX(%a6),FP_SCR0_EX(%a6) + clr.w 2+FP_SCR0(%a6) + mov.l FP_SRC_HI(%a6),%d0 + bset &30,%d0 + mov.l %d0,FP_SCR0_HI(%a6) + mov.l FP_SRC_LO(%a6),FP_SCR0_LO(%a6) + + btst &0x5,EXC_SR(%a6) # supervisor mode exception? + bne.b fsnan_out_x_s # yes + + mov.l %usp,%a0 # fetch user stack pointer + mov.l %a0,EXC_A7(%a6) # save on stack for calc_ea() + mov.l (%a6),EXC_A6(%a6) + + bsr.l _calc_ea_fout # find the correct ea,update An + mov.l %a0,%a1 + mov.l %a0,EXC_EA(%a6) # stack correct + + mov.l EXC_A7(%a6),%a0 + mov.l %a0,%usp # restore user stack pointer + mov.l EXC_A6(%a6),(%a6) + +fsnan_out_x_save: + lea FP_SCR0(%a6),%a0 # pass: ptr to operand + movq.l &0xc,%d0 # pass: size of extended + bsr.l _dmem_write # write the default result + + tst.l %d1 # did dstore fail? + bne.l facc_out_x # yes + + bra.w fsnan_exit + +fsnan_out_x_s: + mov.l (%a6),EXC_A6(%a6) + + bsr.l _calc_ea_fout # find the correct ea,update An + mov.l %a0,%a1 + mov.l %a0,EXC_EA(%a6) # stack correct + + mov.l EXC_A6(%a6),(%a6) + + cmpi.b SPCOND_FLG(%a6),&mda7_flg # is mode -(a7)? + bne.b fsnan_out_x_save # no + +# the operation was "fmove.x SNAN,-(a7)" from supervisor mode. + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + frestore FP_SRC(%a6) + + mov.l EXC_A6(%a6),%a6 # restore frame pointer + + mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp) + mov.l LOCAL_SIZE+EXC_PC+0x2(%sp),LOCAL_SIZE+EXC_PC+0x2-0xc(%sp) + mov.l LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp) + + mov.l LOCAL_SIZE+FP_SCR0_EX(%sp),LOCAL_SIZE+EXC_SR(%sp) + mov.l LOCAL_SIZE+FP_SCR0_HI(%sp),LOCAL_SIZE+EXC_PC+0x2(%sp) + mov.l LOCAL_SIZE+FP_SCR0_LO(%sp),LOCAL_SIZE+EXC_EA(%sp) + + add.l &LOCAL_SIZE-0x8,%sp + + bra.l _real_snan + +######################################################################### +# XDEF **************************************************************** # +# _fpsp_inex(): 060FPSP entry point for FP Inexact exception. # +# # +# This handler should be the first code executed upon taking the # +# FP Inexact exception in an operating system. # +# # +# XREF **************************************************************** # +# _imem_read_long() - read instruction longword # +# fix_skewed_ops() - adjust src operand in fsave frame # +# set_tag_x() - determine optype of src/dst operands # +# store_fpreg() - store opclass 0 or 2 result to FP regfile # +# unnorm_fix() - change UNNORM operands to NORM or ZERO # +# load_fpn2() - load dst operand from FP regfile # +# smovcr() - emulate an "fmovcr" instruction # +# fout() - emulate an opclass 3 instruction # +# tbl_unsupp - add of table of emulation routines for opclass 0,2 # +# _real_inex() - "callout" to operating system inexact handler # +# # +# INPUT *************************************************************** # +# - The system stack contains the FP Inexact exception frame # +# - The fsave frame contains the source operand # +# # +# OUTPUT ************************************************************** # +# - The system stack is unchanged # +# - The fsave frame contains the adjusted src op for opclass 0,2 # +# # +# ALGORITHM *********************************************************** # +# In a system where the FP Inexact exception is enabled, the goal # +# is to get to the handler specified at _real_inex(). But, on the 060, # +# for opclass zero and two instruction taking this exception, the # +# hardware doesn't store the correct result to the destination FP # +# register as did the '040 and '881/2. This handler must emulate the # +# instruction in order to get this value and then store it to the # +# correct register before calling _real_inex(). # +# For opclass 3 instructions, the 060 doesn't store the default # +# inexact result out to memory or data register file as it should. # +# This code must emulate the move out by calling fout() before finally # +# exiting through _real_inex(). # +# # +######################################################################### + + global _fpsp_inex +_fpsp_inex: + + link.w %a6,&-LOCAL_SIZE # init stack frame + + fsave FP_SRC(%a6) # grab the "busy" frame + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack + +# the FPIAR holds the "current PC" of the faulting instruction + mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6) + + mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr + addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr + bsr.l _imem_read_long # fetch the instruction words + mov.l %d0,EXC_OPWORD(%a6) + +############################################################################## + + btst &13,%d0 # is instr an fmove out? + bne.w finex_out # fmove out + + +# the hardware, for "fabs" and "fneg" w/ a long source format, puts the +# longword integer directly into the upper longword of the mantissa along +# w/ an exponent value of 0x401e. we convert this to extended precision here. + bfextu %d0{&19:&3},%d0 # fetch instr size + bne.b finex_cont # instr size is not long + cmpi.w FP_SRC_EX(%a6),&0x401e # is exponent 0x401e? + bne.b finex_cont # no + fmov.l &0x0,%fpcr + fmov.l FP_SRC_HI(%a6),%fp0 # load integer src + fmov.x %fp0,FP_SRC(%a6) # store integer as extended precision + mov.w &0xe001,0x2+FP_SRC(%a6) + +finex_cont: + lea FP_SRC(%a6),%a0 # pass: ptr to src op + bsr.l fix_skewed_ops # fix src op + +# Here, we zero the ccode and exception byte field since we're going to +# emulate the whole instruction. Notice, though, that we don't kill the +# INEX1 bit. This is because a packed op has long since been converted +# to extended before arriving here. Therefore, we need to retain the +# INEX1 bit from when the operand was first converted. + andi.l &0x00ff01ff,USER_FPSR(%a6) # zero all but accured field + + fmov.l &0x0,%fpcr # zero current control regs + fmov.l &0x0,%fpsr + + bfextu EXC_EXTWORD(%a6){&0:&6},%d1 # extract upper 6 of cmdreg + cmpi.b %d1,&0x17 # is op an fmovecr? + beq.w finex_fmovcr # yes + + lea FP_SRC(%a6),%a0 # pass: ptr to src op + bsr.l set_tag_x # tag the operand type + mov.b %d0,STAG(%a6) # maybe NORM,DENORM + +# bits four and five of the fp extension word separate the monadic and dyadic +# operations that can pass through fpsp_inex(). remember that fcmp and ftst +# will never take this exception, but fsincos will. + btst &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic? + beq.b finex_extract # monadic + + btst &0x4,1+EXC_CMDREG(%a6) # is operation an fsincos? + bne.b finex_extract # yes + + bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg + bsr.l load_fpn2 # load dst into FP_DST + + lea FP_DST(%a6),%a0 # pass: ptr to dst op + bsr.l set_tag_x # tag the operand type + cmpi.b %d0,&UNNORM # is operand an UNNORM? + bne.b finex_op2_done # no + bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO +finex_op2_done: + mov.b %d0,DTAG(%a6) # save dst optype tag + +finex_extract: + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd prec/mode + + mov.b 1+EXC_CMDREG(%a6),%d1 + andi.w &0x007f,%d1 # extract extension + + lea FP_SRC(%a6),%a0 + lea FP_DST(%a6),%a1 + + mov.l (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr + jsr (tbl_unsupp.l,%pc,%d1.l*1) + +# the operation has been emulated. the result is in fp0. +finex_save: + bfextu EXC_CMDREG(%a6){&6:&3},%d0 + bsr.l store_fpreg + +finex_exit: + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + frestore FP_SRC(%a6) + + unlk %a6 + bra.l _real_inex + +finex_fmovcr: + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd prec,mode + mov.b 1+EXC_CMDREG(%a6),%d1 + andi.l &0x0000007f,%d1 # pass rom offset + bsr.l smovcr + bra.b finex_save + +######################################################################## + +# +# the hardware does not save the default result to memory on enabled +# inexact exceptions. we do this here before passing control to +# the user inexact handler. +# +# byte, word, and long destination format operations can pass +# through here. so can double and single precision. +# although packed opclass three operations can take inexact +# exceptions, they won't pass through here since they are caught +# first by the unsupported data format exception handler. that handler +# sends them directly to _real_inex() if necessary. +# +finex_out: + + mov.b &NORM,STAG(%a6) # src is a NORM + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # pass rnd prec,mode + + andi.l &0xffff00ff,USER_FPSR(%a6) # zero exception field + + lea FP_SRC(%a6),%a0 # pass ptr to src operand + + bsr.l fout # store the default result + + bra.b finex_exit + +######################################################################### +# XDEF **************************************************************** # +# _fpsp_dz(): 060FPSP entry point for FP DZ exception. # +# # +# This handler should be the first code executed upon taking # +# the FP DZ exception in an operating system. # +# # +# XREF **************************************************************** # +# _imem_read_long() - read instruction longword from memory # +# fix_skewed_ops() - adjust fsave operand # +# _real_dz() - "callout" exit point from FP DZ handler # +# # +# INPUT *************************************************************** # +# - The system stack contains the FP DZ exception stack. # +# - The fsave frame contains the source operand. # +# # +# OUTPUT ************************************************************** # +# - The system stack contains the FP DZ exception stack. # +# - The fsave frame contains the adjusted source operand. # +# # +# ALGORITHM *********************************************************** # +# In a system where the DZ exception is enabled, the goal is to # +# get to the handler specified at _real_dz(). But, on the 060, when the # +# exception is taken, the input operand in the fsave state frame may # +# be incorrect for some cases and need to be adjusted. So, this package # +# adjusts the operand using fix_skewed_ops() and then branches to # +# _real_dz(). # +# # +######################################################################### + + global _fpsp_dz +_fpsp_dz: + + link.w %a6,&-LOCAL_SIZE # init stack frame + + fsave FP_SRC(%a6) # grab the "busy" frame + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack + +# the FPIAR holds the "current PC" of the faulting instruction + mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6) + + mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr + addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr + bsr.l _imem_read_long # fetch the instruction words + mov.l %d0,EXC_OPWORD(%a6) + +############################################################################## + + +# here, we simply see if the operand in the fsave frame needs to be "unskewed". +# this would be the case for opclass two operations with a source zero +# in the sgl or dbl format. + lea FP_SRC(%a6),%a0 # pass: ptr to src op + bsr.l fix_skewed_ops # fix src op + +fdz_exit: + fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + frestore FP_SRC(%a6) + + unlk %a6 + bra.l _real_dz + +######################################################################### +# XDEF **************************************************************** # +# _fpsp_fline(): 060FPSP entry point for "Line F emulator" exc. # +# # +# This handler should be the first code executed upon taking the # +# "Line F Emulator" exception in an operating system. # +# # +# XREF **************************************************************** # +# _fpsp_unimp() - handle "FP Unimplemented" exceptions # +# _real_fpu_disabled() - handle "FPU disabled" exceptions # +# _real_fline() - handle "FLINE" exceptions # +# _imem_read_long() - read instruction longword # +# # +# INPUT *************************************************************** # +# - The system stack contains a "Line F Emulator" exception # +# stack frame. # +# # +# OUTPUT ************************************************************** # +# - The system stack is unchanged # +# # +# ALGORITHM *********************************************************** # +# When a "Line F Emulator" exception occurs, there are 3 possible # +# exception types, denoted by the exception stack frame format number: # +# (1) FPU unimplemented instruction (6 word stack frame) # +# (2) FPU disabled (8 word stack frame) # +# (3) Line F (4 word stack frame) # +# # +# This module determines which and forks the flow off to the # +# appropriate "callout" (for "disabled" and "Line F") or to the # +# correct emulation code (for "FPU unimplemented"). # +# This code also must check for "fmovecr" instructions w/ a # +# non-zero field. These may get flagged as "Line F" but should # +# really be flagged as "FPU Unimplemented". (This is a "feature" on # +# the '060. # +# # +######################################################################### + + global _fpsp_fline +_fpsp_fline: + +# check to see if this exception is a "FP Unimplemented Instruction" +# exception. if so, branch directly to that handler's entry point. + cmpi.w 0x6(%sp),&0x202c + beq.l _fpsp_unimp + +# check to see if the FPU is disabled. if so, jump to the OS entry +# point for that condition. + cmpi.w 0x6(%sp),&0x402c + beq.l _real_fpu_disabled + +# the exception was an "F-Line Illegal" exception. we check to see +# if the F-Line instruction is an "fmovecr" w/ a non-zero . if +# so, convert the F-Line exception stack frame to an FP Unimplemented +# Instruction exception stack frame else branch to the OS entry +# point for the F-Line exception handler. + link.w %a6,&-LOCAL_SIZE # init stack frame + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + + mov.l EXC_PC(%a6),EXC_EXTWPTR(%a6) + mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr + addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr + bsr.l _imem_read_long # fetch instruction words + + bfextu %d0{&0:&10},%d1 # is it an fmovecr? + cmpi.w %d1,&0x03c8 + bne.b fline_fline # no + + bfextu %d0{&16:&6},%d1 # is it an fmovecr? + cmpi.b %d1,&0x17 + bne.b fline_fline # no + +# it's an fmovecr w/ a non-zero that has entered through +# the F-Line Illegal exception. +# so, we need to convert the F-Line exception stack frame into an +# FP Unimplemented Instruction stack frame and jump to that entry +# point. +# +# but, if the FPU is disabled, then we need to jump to the FPU diabled +# entry point. + movc %pcr,%d0 + btst &0x1,%d0 + beq.b fline_fmovcr + + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + unlk %a6 + + sub.l &0x8,%sp # make room for "Next PC", + mov.w 0x8(%sp),(%sp) + mov.l 0xa(%sp),0x2(%sp) # move "Current PC" + mov.w &0x402c,0x6(%sp) + mov.l 0x2(%sp),0xc(%sp) + addq.l &0x4,0x2(%sp) # set "Next PC" + + bra.l _real_fpu_disabled + +fline_fmovcr: + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + unlk %a6 + + fmov.l 0x2(%sp),%fpiar # set current PC + addq.l &0x4,0x2(%sp) # set Next PC + + mov.l (%sp),-(%sp) + mov.l 0x8(%sp),0x4(%sp) + mov.b &0x20,0x6(%sp) + + bra.l _fpsp_unimp + +fline_fline: + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + unlk %a6 + + bra.l _real_fline + +######################################################################### +# XDEF **************************************************************** # +# _fpsp_unimp(): 060FPSP entry point for FP "Unimplemented # +# Instruction" exception. # +# # +# This handler should be the first code executed upon taking the # +# FP Unimplemented Instruction exception in an operating system. # +# # +# XREF **************************************************************** # +# _imem_read_{word,long}() - read instruction word/longword # +# load_fop() - load src/dst ops from memory and/or FP regfile # +# store_fpreg() - store opclass 0 or 2 result to FP regfile # +# tbl_trans - addr of table of emulation routines for trnscndls # +# _real_access() - "callout" for access error exception # +# _fpsp_done() - "callout" for exit; work all done # +# _real_trace() - "callout" for Trace enabled exception # +# smovcr() - emulate "fmovecr" instruction # +# funimp_skew() - adjust fsave src ops to "incorrect" value # +# _ftrapcc() - emulate an "ftrapcc" instruction # +# _fdbcc() - emulate an "fdbcc" instruction # +# _fscc() - emulate an "fscc" instruction # +# _real_trap() - "callout" for Trap exception # +# _real_bsun() - "callout" for enabled Bsun exception # +# # +# INPUT *************************************************************** # +# - The system stack contains the "Unimplemented Instr" stk frame # +# # +# OUTPUT ************************************************************** # +# If access error: # +# - The system stack is changed to an access error stack frame # +# If Trace exception enabled: # +# - The system stack is changed to a Trace exception stack frame # +# Else: (normal case) # +# - Correct result has been stored as appropriate # +# # +# ALGORITHM *********************************************************** # +# There are two main cases of instructions that may enter here to # +# be emulated: (1) the FPgen instructions, most of which were also # +# unimplemented on the 040, and (2) "ftrapcc", "fscc", and "fdbcc". # +# For the first set, this handler calls the routine load_fop() # +# to load the source and destination (for dyadic) operands to be used # +# for instruction emulation. The correct emulation routine is then # +# chosen by decoding the instruction type and indexing into an # +# emulation subroutine index table. After emulation returns, this # +# handler checks to see if an exception should occur as a result of the # +# FP instruction emulation. If so, then an FP exception of the correct # +# type is inserted into the FPU state frame using the "frestore" # +# instruction before exiting through _fpsp_done(). In either the # +# exceptional or non-exceptional cases, we must check to see if the # +# Trace exception is enabled. If so, then we must create a Trace # +# exception frame from the current exception frame and exit through # +# _real_trace(). # +# For "fdbcc", "ftrapcc", and "fscc", the emulation subroutines # +# _fdbcc(), _ftrapcc(), and _fscc() respectively are used. All three # +# may flag that a BSUN exception should be taken. If so, then the # +# current exception stack frame is converted into a BSUN exception # +# stack frame and an exit is made through _real_bsun(). If the # +# instruction was "ftrapcc" and a Trap exception should result, a Trap # +# exception stack frame is created from the current frame and an exit # +# is made through _real_trap(). If a Trace exception is pending, then # +# a Trace exception frame is created from the current frame and a jump # +# is made to _real_trace(). Finally, if none of these conditions exist, # +# then the handler exits though the callout _fpsp_done(). # +# # +# In any of the above scenarios, if a _mem_read() or _mem_write() # +# "callout" returns a failing value, then an access error stack frame # +# is created from the current stack frame and an exit is made through # +# _real_access(). # +# # +######################################################################### + +# +# FP UNIMPLEMENTED INSTRUCTION STACK FRAME: +# +# ***************** +# * * => of fp unimp instr. +# - EA - +# * * +# ***************** +# * 0x2 * 0x02c * => frame format and vector offset(vector #11) +# ***************** +# * * +# - Next PC - => PC of instr to execute after exc handling +# * * +# ***************** +# * SR * => SR at the time the exception was taken +# ***************** +# +# Note: the !NULL bit does not get set in the fsave frame when the +# machine encounters an fp unimp exception. Therefore, it must be set +# before leaving this handler. +# + global _fpsp_unimp +_fpsp_unimp: + + link.w %a6,&-LOCAL_SIZE # init stack frame + + movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 + fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs + fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 + + btst &0x5,EXC_SR(%a6) # user mode exception? + bne.b funimp_s # no; supervisor mode + +# save the value of the user stack pointer onto the stack frame +funimp_u: + mov.l %usp,%a0 # fetch user stack pointer + mov.l %a0,EXC_A7(%a6) # store in stack frame + bra.b funimp_cont + +# store the value of the supervisor stack pointer BEFORE the exc occurred. +# old_sp is address just above stacked effective address. +funimp_s: + lea 4+EXC_EA(%a6),%a0 # load old a7' + mov.l %a0,EXC_A7(%a6) # store a7' + mov.l %a0,OLD_A7(%a6) # make a copy + +funimp_cont: + +# the FPIAR holds the "current PC" of the faulting instruction. + mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6) + + mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr + addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr + bsr.l _imem_read_long # fetch the instruction words + mov.l %d0,EXC_OPWORD(%a6) + +############################################################################ + + fmov.l &0x0,%fpcr # clear FPCR + fmov.l &0x0,%fpsr # clear FPSR + + clr.b SPCOND_FLG(%a6) # clear "special case" flag + +# Divide the fp instructions into 8 types based on the TYPE field in +# bits 6-8 of the opword(classes 6,7 are undefined). +# (for the '060, only two types can take this exception) +# bftst %d0{&7:&3} # test TYPE + btst &22,%d0 # type 0 or 1 ? + bne.w funimp_misc # type 1 + +######################################### +# TYPE == 0: General instructions # +######################################### +funimp_gen: + + clr.b STORE_FLG(%a6) # clear "store result" flag + +# clear the ccode byte and exception status byte + andi.l &0x00ff00ff,USER_FPSR(%a6) + + bfextu %d0{&16:&6},%d1 # extract upper 6 of cmdreg + cmpi.b %d1,&0x17 # is op an fmovecr? + beq.w funimp_fmovcr # yes + +funimp_gen_op: + bsr.l _load_fop # load + + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 # fetch rnd mode + + mov.b 1+EXC_CMDREG(%a6),%d1 + andi.w &0x003f,%d1 # extract extension bits + lsl.w &0x3,%d1 # shift right 3 bits + or.b STAG(%a6),%d1 # insert src optag bits + + lea FP_DST(%a6),%a1 # pass dst ptr in a1 + lea FP_SRC(%a6),%a0 # pass src ptr in a0 + + mov.w (tbl_trans.w,%pc,%d1.w*2),%d1 + jsr (tbl_trans.w,%pc,%d1.w*1) # emulate + +funimp_fsave: + mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions enabled + bne.w funimp_ena # some are enabled + +funimp_store: + bfextu EXC_CMDREG(%a6){&6:&3},%d0 # fetch Dn + bsr.l store_fpreg # store result to fp regfile + +funimp_gen_exit: + fmovm.x EXC_FP0(%a6),&0xc0 # restore fp0-fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + +funimp_gen_exit_cmp: + cmpi.b SPCOND_FLG(%a6),&mia7_flg # was the ea mode (sp)+ ? + beq.b funimp_gen_exit_a7 # yes + + cmpi.b SPCOND_FLG(%a6),&mda7_flg # was the ea mode -(sp) ? + beq.b funimp_gen_exit_a7 # yes + +funimp_gen_exit_cont: + unlk %a6 + +funimp_gen_exit_cont2: + btst &0x7,(%sp) # is trace on? + beq.l _fpsp_done # no + +# this catches a problem with the case where an exception will be re-inserted +# into the machine. the frestore has already been executed...so, the fmov.l +# alone of the control register would trigger an unwanted exception. +# until I feel like fixing this, we'll sidestep the exception. + fsave -(%sp) + fmov.l %fpiar,0x14(%sp) # "Current PC" is in FPIAR + frestore (%sp)+ + mov.w &0x2024,0x6(%sp) # stk fmt = 0x2; voff = 0x24 + bra.l _real_trace + +funimp_gen_exit_a7: + btst &0x5,EXC_SR(%a6) # supervisor or user mode? + bne.b funimp_gen_exit_a7_s # supervisor + + mov.l %a0,-(%sp) + mov.l EXC_A7(%a6),%a0 + mov.l %a0,%usp + mov.l (%sp)+,%a0 + bra.b funimp_gen_exit_cont + +# if the instruction was executed from supervisor mode and the addressing +# mode was (a7)+, then the stack frame for the rte must be shifted "up" +# "n" bytes where "n" is the size of the src operand type. +# f.{b,w,l,s,d,x,p} +funimp_gen_exit_a7_s: + mov.l %d0,-(%sp) # save d0 + mov.l EXC_A7(%a6),%d0 # load new a7' + sub.l OLD_A7(%a6),%d0 # subtract old a7' + mov.l 0x2+EXC_PC(%a6),(0x2+EXC_PC,%a6,%d0) # shift stack frame + mov.l EXC_SR(%a6),(EXC_SR,%a6,%d0) # shift stack frame + mov.w %d0,EXC_SR(%a6) # store incr number + mov.l (%sp)+,%d0 # restore d0 + + unlk %a6 + + add.w (%sp),%sp # stack frame shifted + bra.b funimp_gen_exit_cont2 + +###################### +# fmovecr.x #ccc,fpn # +###################### +funimp_fmovcr: + clr.l %d0 + mov.b FPCR_MODE(%a6),%d0 + mov.b 1+EXC_CMDREG(%a6),%d1 + andi.l &0x0000007f,%d1 # pass rom offset in d1 + bsr.l smovcr + bra.w funimp_fsave + +######################################################################### + +# +# the user has enabled some exceptions. we figure not to see this too +# often so that's why it gets lower priority. +# +funimp_ena: + +# was an exception set that was also enabled? + and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enabled and set + bfffo %d0{&24:&8},%d0 # find highest priority exception + bne.b funimp_exc # at least one was set + +# no exception that was enabled was set BUT if we got an exact overflow +# and overflow wasn't enabled but inexact was (yech!) then this is +# an inexact exception; otherwise, return to normal non-exception flow. + btst &ovfl_bit,FPSR_EXCEPT(%a6) # did overflow occur? + beq.w funimp_store # no; return to normal flow + +# the overflow w/ exact result happened but was inexact set in the FPCR? +funimp_ovfl: + btst &inex2_bit,FPCR_ENABLE(%a6) # is inexact enabled? + beq.w funimp_store # no; return to normal flow + bra.b funimp_exc_ovfl # yes + +# some exception happened that was actually enabled. +# we'll insert this new exception into the FPU and then return. +funimp_exc: + subi.l &24,%d0 # fix offset to be 0-8 + cmpi.b %d0,&0x6 # is exception INEX? + bne.b funimp_exc_force # no + +# the enabled exception was inexact. so, if it occurs with an overflow +# or underflow that was disabled, then we have to force an overflow or +# underflow frame. the eventual overflow or underflow handler will see that +# it's actually an inexact and act appropriately. this is the only easy +# way to have the EXOP available for the enabled inexact handler when +# a disabled overflow or underflow has also happened. + btst &ovfl_bit,FPSR_EXCEPT(%a6) # did overflow occur? + bne.b funimp_exc_ovfl # yes + btst &unfl_bit,FPSR_EXCEPT(%a6) # did underflow occur? + bne.b funimp_exc_unfl # yes + +# force the fsave exception status bits to signal an exception of the +# appropriate type. don't forget to "skew" the source operand in case we +# "unskewed" the one the hardware initially gave us. +funimp_exc_force: + mov.l %d0,-(%sp) # save d0 + bsr.l funimp_skew # check for special case + mov.l (%sp)+,%d0 # restore d0 + mov.w (tbl_funimp_except.b,%pc,%d0.w*2),2+FP_SRC(%a6) + bra.b funimp_gen_exit2 # exit with frestore + +tbl_funimp_except: + short 0xe002, 0xe006, 0xe004, 0xe005 + short 0xe003, 0xe002, 0xe001, 0xe001 + +# insert an overflow frame +funimp_exc_ovfl: + bsr.l funimp_skew # check for special case + mov.w &0xe005,2+FP_SRC(%a6) + bra.b funimp_gen_exit2 + +# insert an underflow frame +funimp_exc_unfl: + bsr.l funimp_skew # check for special case + mov.w &0xe003,2+FP_SRC(%a6) + +# this is the general exit point for an enabled exception that will be +# restored into the machine for the instruction just emulated. +funimp_gen_exit2: + fmovm.x EXC_FP0(%a6),&0xc0 # restore fp0-fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + frestore FP_SRC(%a6) # insert exceptional status + + bra.w funimp_gen_exit_cmp + +############################################################################ + +# +# TYPE == 1: FDB, FS, FTRAP +# +# These instructions were implemented on the '881/2 and '040 in hardware but +# are emulated in software on the '060. +# +funimp_misc: + bfextu %d0{&10:&3},%d1 # extract mode field + cmpi.b %d1,&0x1 # is it an fdb? + beq.w funimp_fdbcc # yes + cmpi.b %d1,&0x7 # is it an fs? + bne.w funimp_fscc # yes + bfextu %d0{&13:&3},%d1 + cmpi.b %d1,&0x2 # is it an fs? + blt.w funimp_fscc # yes + +######################### +# ftrap # +# ftrap.w # # +# ftrap.l # # +######################### +funimp_ftrapcc: + + bsr.l _ftrapcc # FTRAP() + + cmpi.b SPCOND_FLG(%a6),&fbsun_flg # is enabled bsun occurring? + beq.w funimp_bsun # yes + + cmpi.b SPCOND_FLG(%a6),&ftrapcc_flg # should a trap occur? + bne.w funimp_done # no + +# FP UNIMP FRAME TRAP FRAME +# ***************** ***************** +# ** ** ** Current PC ** +# ***************** ***************** +# * 0x2 * 0x02c * * 0x2 * 0x01c * +# ***************** ***************** +# ** Next PC ** ** Next PC ** +# ***************** ***************** +# * SR * * SR * +# ***************** ***************** +# (6 words) (6 words) +# +# the ftrapcc instruction should take a trap. so, here we must create a +# trap stack frame from an unimplemented fp instruction stack frame and +# jump to the user supplied entry point for the trap exception +funimp_ftrapcc_tp: + mov.l USER_FPIAR(%a6),EXC_EA(%a6) # Address = Current PC + mov.w &0x201c,EXC_VOFF(%a6) # Vector Offset = 0x01c + + fmovm.x EXC_FP0(%a6),&0xc0 # restore fp0-fp1 + fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs + movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 + + unlk %a6 + bra.l _real_trap + +######################### +# fdb Dn,