diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/CREDITS linux.ac/CREDITS
--- linux.vanilla/CREDITS Tue Feb 23 14:21:32 1999
+++ linux.ac/CREDITS Fri Feb 26 01:47:18 1999
@@ -1061,6 +1061,14 @@
S: L3R 8B2
S: Canada
+N: Russell Kroll
+E: rkroll@exploits.org
+W: http://www.exploits.org/
+D: V4L Aztech radio card driver, mods to Aimslab driver
+S: Post Office Box 49458
+S: Colorado Springs, Colorado 80949-9458
+S: USA
+
N: Gero Kuhlmann
E: gero@gkminix.han.de
D: mounting root via NFS
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/Changes linux.ac/Documentation/Changes
--- linux.vanilla/Documentation/Changes Sun Jan 24 19:55:29 1999
+++ linux.ac/Documentation/Changes Tue Feb 16 17:11:41 1999
@@ -250,6 +250,11 @@
The ISDN code in the stock 2.0 kernel may not work for you. If it
doesn't, look in ftp://ftp.suse.com/pub/isdn4linux for updated versions.
+ In 2.0.x the kernel could be configured to drop source routed IP
+packets via a compile time configuration option. In 2.2.x, this has
+been replaced by a sysctl. See Documentation/networking/ip-sysctl.txt
+for more information.
+
Memory
======
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/Configure.help linux.ac/Documentation/Configure.help
--- linux.vanilla/Documentation/Configure.help Tue Feb 23 14:21:32 1999
+++ linux.ac/Documentation/Configure.help Mon Mar 1 00:29:24 1999
@@ -85,13 +85,13 @@
a system with only one CPU, like most personal computers, say N. If
you have a system with more than one CPU, say Y.
- If you say N here, the kernel will run on single and multiprocessor
- machines, but will use only one CPU of a multiprocessor machine. If
+ If you say N here, the kernel will run on single and multi-processor
+ machines, but will use only one CPU of a multi-processor machine. If
you say Y here, the kernel will run on many, but not all,
- singleprocessor machines. On a singleprocessor machine, the kernel
+ single-processor machines. On a single-processor machine, the kernel
will run faster if you say N here.
- Note that if you say Y here and choose architecture "586" or
+ Note that if you say Y here and choose architectures "586" or
"Pentium" under "Processor family", the kernel will not work on 486
architectures. Similarly, multiprocessor kernels for the "PPro"
architecture may not work on all Pentium based boards.
@@ -1089,25 +1089,6 @@
recommended to read the NET-3-HOWTO, available via FTP (user:
anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
-Network aliasing
-CONFIG_NET_ALIAS
- If you say Y here, you will be able to set multiple network
- addresses on the same low-level network device driver. This is
- typically used for services that act differently based on the
- address they listen on (e.g. "multihosting" or "virtual domains" or
- "virtual hosting services" on the web server apache and the ftp
- server wuftpd -- read the Virtual-Services-HOWTO, available via FTP
- (user: anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO)
- or for connecting to different logical networks through the same
- physical interface (most commonly an Ethernet networking card). See
- Documentation/networking/alias.txt for more info.
-
- This is the generic part, later when configuring network protocol
- options you will be asked for protocol-specific aliasing support,
- and you will have to say Y to at least one of them, most likely to
- "IP: aliasing support". If you need this feature (for any protocol,
- like IP) say Y; if unsure, say N.
-
Socket filtering
CONFIG_FILTER
The Linux Socket Filter is derived from the Berkeley Packet Filter.
@@ -1762,6 +1743,18 @@
except that your Apollo won't be able to boot from it (because the
code in the ROM will be for a PC).
+Apollo support
+CONFIG_APOLLO
+ Say Y here if you want to run Linux on an MC680x0-based Apollo
+ Domain workstation such as the DN3500.
+
+Apollo 3c505 support
+CONFIG_APOLLO_ELPLUS
+ Say Y or M here if your Apollo has a 3Com 3c505 ISA Ethernet card.
+ If you don't have one made for Apollos, you can use one from a PC,
+ except that your Apollo won't be able to boot from it (because the
+ code in the ROM will be for a PC).
+
Atari native chipset support
CONFIG_FB_ATARI
This is the frame buffer device driver for the builtin graphics
@@ -2099,7 +2092,7 @@
CONFIG_PNP_PARPORT
Some IEEE-1284 conforming parallel-port devices can identify
themselves when requested. Say Y to enable this feature, or M to
- compile it as a module (parport_ieee1284.o). If in doubt, say N.
+ compile it as a module (parport_probe.o). If in doubt, say N.
Enable loadable module support
CONFIG_MODULES
@@ -2735,20 +2728,6 @@
enabled. Those programs that would benefit from disabling this
facility can do it on a per connection basis themselves.
-IP: Drop source routed frames
-CONFIG_IP_NOSR
- Usually, the originator of an IP frame (packet) specifies only the
- destination, and the hosts along the way do the routing, i.e. they
- decide how to forward the frame. However, there is a feature of the
- IP protocol that allows to specify the full route for a given frame
- already at its origin. A frame with such a fully specified route is
- called "source routed". The question now is whether we should honour
- these route requests when such frames arrive, or if we should drop
- all those frames instead. Honouring them can introduce security
- problems (and is rarely a useful feature), and hence it is
- recommended that you say Y here unless you really know what you're
- doing.
-
IP: Allow large windows (not recommended if <16 MB of memory)
CONFIG_SKB_LARGE
On high speed, long distance networks the performance limit on
@@ -3712,34 +3691,49 @@
say M here and read Documentation/modules.txt. The module will be
called aic7xxx.o.
-Override driver defaults for commands per LUN
-CONFIG_OVERRIDE_CMDS
- Say Y here if you want to override the default maximum number of
- commands that a single device on the aic7xxx controller is allowed
- to have active at one time. This option only affects tagged queueing
- capable devices. The driver uses a value of 24 by default.
- If you say Y here, you can adjust the number of commands per LUN
- with the following configuration option.
-
- If unsure, say N.
+Enable or Disable Tagged Command Queueing by default
+CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
+ This option causes the aic7xxx driver to attempt to use tagged command
+ queueing on any devices that claim to support it. If this is set to yes,
+ you can still turn off TCQ on troublesome devices with the use of the
+ tag_info boot parameter. See /usr/src/linux/drivers/scsi/README.aic7xxx
+ for more information on that and other aic7xxx setup commands. If this
+ option is turned off, you may still enable TCQ on known good devices by
+ use of the tag_info boot parameter.
+
+ If you are unsure about your devices then it is safest to say N here.
+
+ However, TCQ can increase performance on some hard drives by as much
+ as 50% or more, so I would recommend that if you say N here, that you
+ at least read the README.aic7xxx file so you will know how to enable
+ this option manually should your drives prove to be safe in regards
+ to TCQ.
+
+ Conversely, certain drives are known to lock up or cause bus resets when
+ TCQ is enabled on them. If you have a Western Digital Enterprise SCSI
+ drive for instance, then don't even bother to enable TCQ on it as the
+ drive will become unreliable, and it will actually reduce performance.
+
+Default number of TCQ commands per device
+CONFIG_AIC7XXX_CMDS_PER_DEVICE
+ Specify the number of commands you would like to allocate per SCSI
+ device when Tagged Command Queueing (TCQ) is enabled on that device.
-Maximum number of commands per LUN
-CONFIG_AIC7XXX_CMDS_PER_LUN
- Specify the maximum number of commands you would like to allocate
- per LUN (a LUN is a Logical Unit Number -- some physical SCSI
- devices, e.g. CD jukeboxes, act logically as several separate units,
- each of which gets its own number).
-
- Reasonable figures are in the range of 14 to 32 commands per device,
+ Reasonable figures are in the range of 8 to 24 commands per device,
but depending on hardware could be increased or decreased from that
figure. If the number is too high for any particular device, the
driver will automatically compensate usually after only 10 minutes
- of uptime and will issue a message to alert you to the fact that the
- number of commands for that device has been reduced. It will not
- hinder performance if some of your devices eventually have their
- commands per LUN reduced, but is a waste of memory if all of your
- devices end up reducing this number down to a more reasonable
- figure. Default: 24
+ of uptime. It will not hinder performance if some of your devices
+ eventually have their command depth reduced, but is a waste of memory
+ if all of your devices end up reducing this number down to a more
+ reasonable figure.
+
+ NOTE: Certain very broken drives are known to lock up when given more
+ commands than they like to deal with. Quantum Fireball drives are the
+ most common in this category. For the Quantum Fireball drives I would
+ suggest no more than 8 commands per device.
+
+ Default: 8
Collect statistics to report in /proc
CONFIG_AIC7XXX_PROC_STATS
@@ -4203,6 +4197,17 @@
say M here and read Documentation/modules.txt. The module will be
called initio.o
+Initio 91XXU(W) SCSI support
+CONFIG_SCSI_INITIO
+ This is support for the Initio 91XXU(W) SCSI host adapter.
+ Please read the SCSI-HOWTO, available via FTP (user: anonymous) at
+ ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+
+ If you want to compile this as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want),
+ say M here and read Documentation/modules.txt. The module will be
+ called initio.o
+
PAS16 SCSI support
CONFIG_SCSI_PAS16
This is support for a SCSI host adapter. It is explained in section
@@ -4216,6 +4221,17 @@
The module will be called pas16.o. If you want to compile it as a
module, say M here and read Documentation/modules.txt.
+Initio INI-A100U2W SCSI support
+CONFIG_SCSI_INIA100
+ This is support for the Initio INI-A100U2W SCSI host adapter.
+ Please read the SCSI-HOWTO, available via FTP (user: anonymous) at
+ ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+
+ If you want to compile this as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want),
+ say M here and read Documentation/modules.txt. The module will be
+ called a100u2w.o
+
PCI2000 support
CONFIG_SCSI_PCI2000
This is support for the PCI2000I EIDE interface card which acts as a
@@ -4408,6 +4424,23 @@
say M here and read Documentation/modules.txt. The module will be
called NCR53c406.o.
+Symbios Logic sym53c416 support
+CONFIG_SCSI_SYM53C416
+ This is support for the sym53c416 SCSI host adapter. This is the
+ SCSI adapter that comes with some hp scanners. This driver requires that
+ the sym53c416 is configured first using some sort of pnp configuration
+ program (e.g. isapnp) or by a PnP aware BIOS. If you are using isapnp then
+ you need to compile it as a module and then load it using insmod after
+ isapnp has run. The parameters of the configured card(s) should be passed
+ to the driver. The format is:
+
+ insmod sym53c416 sym53c416=, [sym53c416_1=,]
+
+ There is support for up to four adapters. If you want to compile this
+ driver as a module ( = code which can be inserted in and removed from
+ the running kernel whenever you want), say M here and read
+ Documentation/modules.txt.
+
Tekram DC390(T) and Am53/79C974 (PCscsi) SCSI support
CONFIG_SCSI_DC390T
This driver supports PCI SCSI host adapters based on the Am53C974A
@@ -7034,11 +7067,12 @@
If unsure, say N.
-System V and Coherent filesystem support
+System V, Version 7 and Coherent filesystem support
CONFIG_SYSV_FS
SCO, Xenix and Coherent are commercial Unix systems for Intel
- machines. Saying Y here would allow you to read to and write from
- their floppies and hard disk partitions.
+ machines, and Version 7 was used on the DEC PDP-11. Saying Y here
+ would allow you to read to and write from their floppies and hard disk
+ partitions.
If you have floppies or hard disk partitions like that, it is likely
that they contain binaries from those other Unix systems; in order
@@ -8924,6 +8958,20 @@
here (the module will be called sound.o) if you haven't found a
driver for your sound card above, then pick your driver from the
list below.
+
+Persistent DMA buffers
+CONFIG_SOUND_DMAP
+ Linux can often have problems allocating DMA buffers for ISA cards on
+ machines with more than 16MB of RAM. This is because ISA DMA buffers
+ must exist below the 16MB boundry and it is quite possible that we
+ can't find a large enough free block in this region after the machine
+ has been running for any amount of time. If you say Y here the DMA
+ buffers (64Kb) will be allocated at boot time and kept until the
+ shutdown. This option is only usefull if you say Y to OSS sound
+ modules. If you say M to OSS sound modules then you can just pass to
+ the sound.o module a "dmabuf=1" command-line argument.
+
+ Say Y unless you have 16MB or less RAM or a PCI sound card.
Support for Aztech Sound Galaxy (non-PnP) cards
CONFIG_SOUND_SGALAXY
@@ -9463,6 +9511,11 @@
ISDN subsystem
CONFIG_ISDN
+ CAUTION: the ISDN driver shipped with this kernel distribution
+ is outdated and might not work without problems. An updated driver
+ is available for download. Please read http://www.isdn4linux.de
+ on the WWW for a list of servers.
+
ISDN ("Integrated Services Digital Networks", called RNIS in France)
is a special type of fully digital telephone service; it's mostly
used to connect to your Internet service provider (with SLIP or
@@ -10503,6 +10556,44 @@
CONFIG_RADIO_SF16FMI_PORT
Enter the I/O port of your SF16FMI radio card.
+Typhoon Radio
+CONFIG_RADIO_TYPHOON
+ Choose Y here if you have one of these FM radio cards, and then fill
+ in the port address and the frequency used for muting below.
+
+ In order to control your radio card, you will need to use programs
+ that are compatible with the Video for Linux API. Information on
+ this API and pointers to "v4l" programs may be found on the WWW at
+ http://roadrunner.swansea.uk.linux.org/v4l.shtml; to browse the WWW,
+ you need to have access to a machine on the Internet that has a
+ program like lynx or netscape.
+
+ If you want to compile this driver as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want),
+ say M here and read Documentation/modules.txt. The module will be
+ called radio-typhoon.o
+
+Support for /proc/radio-typhoon
+CONFIG_RADIO_TYPHOON_PROC_FS
+ Say Y here if you want the typhoon radio card driver to write
+ status information (frequency, volume, muted, mute frequency,
+ base address) to /proc/radio-typhoon. The file can be viewed with
+ your favorite pager (i.e. use "more /proc/radio-typhoon" or "less
+ /proc/radio-typhoon" or simply "cat /proc/radio-typhoon").
+
+Typhoon I/O port (0x316 or 0x336)
+CONFIG_RADIO_TYPHOON_PORT
+ Enter the I/O port of your Typhoon or EcoRadio radio card.
+
+Typhoon frequency set when muting the device (kHz)
+CONFIG_RADIO_TYPHOON_MUTEFREQ
+ Enter the frequency used for muting the radio. The device is never
+ completely silent. If the volume is just turned down, you can still
+ hear silent voices and music. For that reason, the frequency of the
+ radio device is set to the frequency you can enter here whenever
+ the device is muted. There should be no local radio station at that
+ frequency.
+
Zoltrix Radio
CONFIG_RADIO_ZOLTRIX
Choose Y here if you have one of these FM radio cards, and then fill
@@ -10748,24 +10839,10 @@
Documentation/modules.txt. IrLAN emulates an Ethernet and makes it
possible to put up a wireless LAN using infrared beams.
-IrLAN Client Protocol
-CONFIG_IRLAN_CLIENT
- Say Y here if you want to build support for the IrLAN client
- protocol. If you want to compile it as a module, say M here and read
- Documentation/modules.txt. The IrLAN client protocol can be used to
- talk with infrared access points like the HP NetbeamIR, or the ESI
- JetEye NET. You can also connect to another Linux machine running
- the IrLAN server protocol for ad-hoc networking!
-
-IrLAN Server Protocol
-CONFIG_IRLAN_SERVER
- Say Y here if you want to build support for infrared LAN access. If
- you want to compile it as a module, say M here and read
- Documentation/modules.txt. The IrLAN server protocol makes it
- possible to set up a wireless LAN with a machine running the IrLAN
- client protocol. Notice that the IrLAN server protocol currently
- only emulates an access point and does not implement the ad-hoc
- specification of IrLAN, but this will not be noticeable by the user.
+ The IrLAN protocol can be used to talk with infrared access points
+ like the HP NetbeamIR, or the ESI JetEye NET. You can also connect
+ to another Linux machine running the IrLAN protocol for ac-hoc
+ networking!
IrOBEX Protocol
CONFIG_IROBEX
@@ -10877,6 +10954,15 @@
the normal 9-pin serial port connector, and can currently only be
used by IrTTY. To activate support for Tekram dongles you will have
to insert "irattach -d tekram" in the /etc/irda/drivers script.
+
+Greenwich GIrBIL dongle
+CONFIG_GIRBIL_DONGLE
+ Say Y here if you want to build support for the Greenwich GIrBIL
+ dongle. If you want to compile it as a module, say M here and read
+ Documentation/modules.txt. The Greenwich dongle attaches to the
+ normal 9-pin serial port connector, and can currently only be used
+ by IrTTY. To activate support for Greenwich dongles you will have to
+ insert "irattach -d girbil" in the /etc/irda/drivers script.
VME (Motorola and BVM) support
CONFIG_VME
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/filesystems/dcache.txt linux.ac/Documentation/filesystems/dcache.txt
--- linux.vanilla/Documentation/filesystems/dcache.txt Thu Jan 1 01:00:00 1970
+++ linux.ac/Documentation/filesystems/dcache.txt Thu Jan 14 04:02:58 1999
@@ -0,0 +1,173 @@
+Some dcache details
+
+A traditional Unix system has inodes (`index nodes') as in-core
+descriptors of files. An inode refers to the actual file, not
+to a directory entry naming it. Linux v2.1.43 introduced dentries
+(`directory entries') as in-core descriptors of file names.
+
+The entire purpose of dentries is to make the map
+filename -> inode fast. An interesting side effect
+is that the kernel knows what name was used to open a file
+and that a system call getcwd() is possible.
+
+Thus, the central part of the dcache code are the lines
+ dentry = reserved_lookup(base, &this);
+ if (!dentry) {
+ dentry = cached_lookup(base, &this);
+ if (!dentry)
+ dentry = real_lookup(base, &this);
+ }
+in namei.c. The reserved_lookup() takes care of . and ..;
+the cached_lookup() is what we have the dcache for,
+and the real_lookup() goes to the filesystem.
+
+The cached_lookup() returns the value of d_lookup(),
+but does a d_revalidate() before returning, and if that fails
+and the dentry has no children, it returns NULL.
+ [This is a rather obscure part. The d_revalidate()
+ is allowed to fail for any reason - for example,
+ autofs uses a timeout to make d_revalidate fail -
+ which means that the final dentry we come up with
+ need not be the dentry that d_lookup() found.
+ This causes bugs in the vfat filesystem.
+ Moreover, if d_revalidate(D) fails but D still has
+ children, then D is used anyway.
+ This also causes bugs in the vfat filesystem.
+ I think also nfs has problems.]
+
+
+
+
+A struct dentry has five members of type struct list_head:
+ struct list_head d_hash; /* lookup hash list */
+ struct list_head d_lru; /* d_count = 0 LRU list */
+ struct list_head d_child; /* child of parent list */
+ struct list_head d_subdirs; /* our children */
+ struct list_head d_alias; /* inode alias list */
+
+ [Some of these names were very badly chosen, and lead
+ to confusion all the time. We should do a global replace
+ changing d_subdirs into d_children and d_child into d_sister.]
+
+
+
+1. d_hash
+
+The d_hash field of a dentry links the dentry into
+the list of dentries for filenames with a given hash value
+with list head dentry_hashtable[hashvalue] defined in dcache.c.
+This list is used in d_lookup() to find a dentry with given name
+and parent. It is used in d_validate() to find a dentry with
+known hash and parent.
+ [The present code takes the parent into account when
+ computing a hash. Not doing this would make the code
+ simpler and faster, possibly at the expense of a few
+ more collisions. Has anyone investigated this?]
+The d_hash field is an empty list when the file is a mount point
+(cf. d_validate) or has been deleted, or when the dentry was
+dropped for some other reason.
+
+
+d_add(D,I) will put D into its hash chain and provide it
+with the inode I. It is called by all filesystem lookup routines.
+
+d_drop(D) will remove D from its hash chain. A dentry is called
+`unhashed' when its d_hash field is an empty list.
+Sometimes dentries are dropped temporarily to make sure
+no lookup will find them. The general routine vfs_rmdir(I,D)
+will drop D if d_count=2, so that all filesystem rmdir()
+routines can return -EBUSY when D still occurs in the hash list.
+The filesystem routines for unlink and rmdir call d_delete()
+which again calls d_drop().
+
+[The d_hash field is referred to in many places that should
+not know about its existence, in the phrase
+ if (list_empty(&dentry->d_hash)) ...
+No doubt there should be a line
+ #define unhashed(d) (list_empty(&(d)->d_hash))
+in dcache.h, together with a comment describing the semantics
+of being unhashed. Then all these occurrences of d_hash can
+be removed. Next, d_drop() should be renamed d_unhash().]
+
+The dentry for the root of a mounted filesystem is returned by
+d_alloc_root() and is unhashed.
+
+
+
+2. d_lru
+The simplest list is the one joining the d_lru fields of
+dentries that had d_count = 0 at some point in time.
+The list head is the variable dentry_unused defined in dcache.c.
+The number of elements in this list is dentry_stat.nr_unused.
+There are no references to the d_lru field outside dcache.[ch].
+
+Note that d_count is incremented by dget(), invoked by d_lookup(),
+without removing the dentry from the LRU list. Thus, anyone hoping
+to find unused dentries on this list must first check d_count.
+If a dentry is not on the LRU list, its d_lru field is an
+empty list (initialized by d_alloc()).
+
+dput(D) tries to get rid of D altogether when d_count = 0, but
+puts D at the head of the LRU list if it is still on the hash list.
+Thus, every D with d_count = 0 will be on the LRU list.
+
+select_dcache(ict,pct) removes D with d_count > 0 from the
+LRU list, and moves D that are ready to be sacrificed for memory
+to the end of the list. (If ict and/or pct is given, then we are
+satisfied when the selected D's involve ict inodes or pct pages.)
+
+prune_dcache(ct) removes D with d_count > 0 from the LRU list,
+and frees unused D, stopping when ct of them have been freed.
+
+shrink_dcache_sb(sb) removes all unused D with given superblock
+from the LRU list.
+
+select_parent(D) move all unused descendants of D to the end
+of the LRU list.
+
+
+
+3. d_child and d_subdirs
+As already noted, the names are terrible. The d_child field
+does not refer to a child but to a sibling, and the d_subdirs
+field does not refer to a subdirectory but to a child, directory
+or not. These two fields form a threaded tree: the d_subdirs field
+points to the first child, and the d_child field is member of the
+circularly linked list of all children of one parent.
+
+To be more precise: this circularly linked list of all children
+of one parent P passes through the d_child fields of all children
+and through the d_subdirs field of the parent P.
+
+
+
+4. d_alias
+Somewhat similar to the above, where we had a circularly linked list
+with one special element, we here have a circularly linked list
+passing through the d_alias field of all dentries that are aliases
+of one inode, and through the i_dentry field of the inode.
+
+The dentry is added to this list by d_instantiate().
+It is removed again by dentry_iput() which is called by dput()
+and d_delete().
+
+
+
+
+So far about the lists in the dentry structure.
+Some of the routines in dcache.c have been mentioned already.
+Let me describe one of the more obscure ones.
+
+d_move(D,T) is the routine called by the filesystem code
+just before finishing the rename(D,T) call. Since both
+dentries D and T may be busy we cannot just throw one away.
+Instead they are partially interchanged:
+D and T interchange names, and D is put into T's hash queue,
+and T is unhashed; D and T interchange parents, and are put
+on the list of children of their new parent.
+The result is that the file D that got renamed is now in perfect
+shape again - it has been renamed. T, if it existed, lost its
+name string, if it was short, but perhaps this is harmless -
+let us hope no-one will ever ask for T's name anymore.
+
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/filesystems/sysv-fs.txt linux.ac/Documentation/filesystems/sysv-fs.txt
--- linux.vanilla/Documentation/filesystems/sysv-fs.txt Sun Nov 8 15:08:46 1998
+++ linux.ac/Documentation/filesystems/sysv-fs.txt Mon Mar 1 00:18:47 1999
@@ -2,20 +2,22 @@
It implements all of
- Xenix FS,
- SystemV/386 FS,
+ - Version 7 FS
- Coherent FS.
This is version beta 4.
To install:
-* Answer the 'System V and Coherent filesystem support' question with 'y'
- when configuring the kernel.
+* Answer the 'System V, Version 7 and Coherent filesystem support' question
+ with a 'y' when configuring the kernel.
* To mount a disk or a partition, use
mount [-r] -t sysv device mountpoint
The file system type names
-t sysv
-t xenix
+ -t v7
-t coherent
- may be used interchangeably, but the last two will eventually disappear.
+ the xenix and coherent options will eventually disappear.
Bugs in the present implementation:
- Coherent FS:
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/sound/CMI8330 linux.ac/Documentation/sound/CMI8330
--- linux.vanilla/Documentation/sound/CMI8330 Thu Jan 1 01:00:00 1970
+++ linux.ac/Documentation/sound/CMI8330 Sat Feb 27 21:02:23 1999
@@ -0,0 +1,85 @@
+How to enable CMI 8330 soundchip on Linux
+------------------------------------------
+Stefan Laudat
+
+Hello folks,
+
+ The CMI8330 soundchip is a very small chip found on many recent
+ motherboards. In order to use it you just have to use a proper
+ isapnp.conf and a little bit of patience.
+
+ Of course you will have to compile kernel sound support as module,
+ as shown below:
+
+CONFIG_SOUND=m
+CONFIG_SOUND_OSS=m
+CONFIG_SOUND_SB=m
+CONFIG_SOUND_ADLIB=m
+CONFIG_SOUND_MPU401=m
+# Just for fun :)
+CONFIG_SOUND_MSS=m
+
+ The /etc/isapnp.conf file will be:
+
+
+
+(READPORT 0x0203)
+(ISOLATE PRESERVE)
+(IDENTIFY *)
+(VERBOSITY 2)
+(CONFLICT (IO FATAL)(IRQ FATAL)(DMA FATAL)(MEM FATAL)) # or WARNING
+(VERIFYLD N)
+# WSS
+
+(CONFIGURE CMI0001/16777472 (LD 0
+(IO 0 (SIZE 8) (BASE 0x0530))
+(IO 1 (SIZE 8) (BASE 0x0388))
+(INT 0 (IRQ 5 (MODE +E)))
+(DMA 0 (CHANNEL 0))
+(NAME "CMI0001/16777472[0]{CMI8330/C3D Audio Adapter}")
+(ACT Y)
+))
+
+# Control device ?
+
+(CONFIGURE CMI0001/16777472 (LD 1
+(IO 0 (SIZE 2) (BASE 0x0330))
+(INT 0 (IRQ 11 (MODE +E)))
+(NAME "CMI0001/16777472[1]{CMI8330/C3D Audio Adapter}")
+(ACT Y)
+))
+
+# Joystick
+
+(CONFIGURE CMI0001/16777472 (LD 2
+(IO 0 (SIZE 8) (BASE 0x0200))
+(NAME "CMI0001/16777472[2]{CMI8330/C3D Audio Adapter}")
+(ACT Y)
+))
+
+# SB...
+(CONFIGURE CMI0001/16777472 (LD 3
+(IO 0 (SIZE 16) (BASE 0x0220))
+(INT 0 (IRQ 7 (MODE +E)))
+(DMA 0 (CHANNEL 1))
+(DMA 1 (CHANNEL 5))
+(NAME "CMI0001/16777472[3]{CMI8330/C3D Audio Adapter}")
+(ACT Y)
+))
+
+
+(WAITFORKEY)
+
+
+
+ The module sequence is trivial:
+
+/sbin/modprobe sound
+/sbin/insmod uart401
+/sbin/insmod sb io=0x220 irq=5 dma=1 dma16=-1
+/sbin/insmod mpu401 io=0x330
+/sbin/insmod opl3 io=0x388
+# In case you want the MSS instead of SB use
+/sbin/insmod ad1848 io=0x530 dma=0 irq=5
+
+ The soundchip is now fully initialized. Enjoy it.
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/MAINTAINERS linux.ac/MAINTAINERS
--- linux.vanilla/MAINTAINERS Tue Feb 23 14:21:32 1999
+++ linux.ac/MAINTAINERS Mon Mar 1 18:24:33 1999
@@ -324,7 +324,7 @@
M: arobinso@nyx.net
L: linux-kernel@vger.rutgers.edu
W: http://www.nyx.net/~arobinso
-S: Maintainted
+S: Maintained
HFS FILESYSTEM
P: Adrian Sun
@@ -637,6 +637,11 @@
L: linux-kernel@vger.rutgers.edu
S: Maintained
+SCSI GENERIC
+L: linux-scsi@vger.rutgers.edu
+M: douglas.gilbert@rbcds.com
+S: Maintained
+
SCSI SUBSYSTEM
L: linux-scsi@vger.rutgers.edu
S: Unmaintained
@@ -678,9 +683,18 @@
S: Supported
SPARC:
+P: David S. Miller
+M: davem@dm.cobaltmicro.com
P: Eddie C. Dost
M: ecd@skynet.be
+P: Jakub Jelinek
+M: jj@sunsite.ms.mff.cuni.cz
+P: Anton Blanchard
+M: anton@jubilex.progsoc.uts.edu.au
L: sparclinux@vger.rutgers.edu
+L: ultralinux@vger.rutgers.edu
+W: http://ultra.linux.cz
+W: http://www.geog.ubc.ca/s_linux.html
S: Maintained
SPECIALIX IO8+ MULTIPORT SERIAL CARD DRIVER
@@ -704,10 +718,8 @@
S: Supported
STARMODE RADIO IP (STRIP) PROTOCOL DRIVER
-P: Stuart Cheshire
-M: cheshire@cs.stanford.edu
W: http://mosquitonet.Stanford.EDU/strip.html
-S: Maintained
+S: Unsupported ?
SVGA HANDLING
P: Martin Mares
@@ -804,4 +816,4 @@
THE REST
P: Linus Torvalds
-S: Buried alive in diapers
+S: Buried alive in reporters
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Makefile linux.ac/Makefile
--- linux.vanilla/Makefile Tue Feb 23 14:21:32 1999
+++ linux.ac/Makefile Tue Mar 2 01:59:31 1999
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 2
SUBLEVEL = 2
-EXTRAVERSION =
+EXTRAVERSION = -ac7
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
@@ -343,7 +343,8 @@
clean: archclean
rm -f kernel/ksyms.lst include/linux/compile.h
- rm -f core `find . -name '*.[oas]' ! -regex '.*lxdialog/.*' -print`
+ rm -f core `find . -name '*.[oas]' ! \( -regex '.*lxdialog/.*' \
+ -o -regex '.*ksymoops/.*' \) -print`
rm -f core `find . -type f -name 'core' -print`
rm -f core `find . -name '.*.flags' -print`
rm -f vmlinux System.map
@@ -367,6 +368,7 @@
rm -f .version .config* config.in config.old
rm -f scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp
rm -f scripts/lxdialog/*.o scripts/lxdialog/lxdialog
+ rm -f scripts/ksymoops/*.o scripts/ksymoops/ksymoops
rm -f .menuconfig.log
rm -f include/asm
rm -rf include/config
@@ -379,8 +381,8 @@
distclean: mrproper
rm -f core `find . \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
- -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
- -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -print` TAGS
+ -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
+ -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -print` TAGS
backup: mrproper
cd .. && tar cf - linux/ | gzip -9 > backup.gz
@@ -389,7 +391,7 @@
sums:
find . -type f -print | sort | xargs sum > .SUMS
-dep-files: scripts/mkdep archdep include/linux/version.h
+dep-files: scripts/mkdep archdep include/linux/version.h new-genksyms
scripts/mkdep init/*.c > .depend
scripts/mkdep `find $(FINDHPATH) -follow -name \*.h ! -name modversions.h -print` > .hdepend
# set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i fastdep ;done
@@ -399,7 +401,19 @@
MODVERFILE :=
ifdef CONFIG_MODVERSIONS
+
MODVERFILE := $(TOPDIR)/include/linux/modversions.h
+
+new-genksyms:
+ @$(GENKSYMS) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) /dev/null || ( echo -e "\nYou need a new version of the genksyms\
+ program, which is part of\nthe modutils package. Please read the file\
+ Documentation/Changes\nfor more information.\n"; exit 1 )
+
+else
+
+new-genksyms:
+
endif
depend dep: dep-files $(MODVERFILE)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/defconfig linux.ac/arch/alpha/defconfig
--- linux.vanilla/arch/alpha/defconfig Mon Dec 28 23:09:39 1998
+++ linux.ac/arch/alpha/defconfig Fri Feb 26 01:59:54 1999
@@ -91,7 +91,6 @@
# CONFIG_PACKET is not set
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
-# CONFIG_NET_ALIAS is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
@@ -108,7 +107,6 @@
# (it is safe to leave these untouched)
#
# CONFIG_INET_RARP is not set
-CONFIG_IP_NOSR=y
CONFIG_SKB_LARGE=y
#
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/process.c linux.ac/arch/alpha/kernel/process.c
--- linux.vanilla/arch/alpha/kernel/process.c Sun Jan 24 19:55:29 1999
+++ linux.ac/arch/alpha/kernel/process.c Sun Jan 24 20:20:25 1999
@@ -55,7 +55,6 @@
unsigned long init_user_stack[1024] = { STACK_MAGIC, };
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
-static struct file * init_fd_array[NR_OPEN] = { NULL, };
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
struct mm_struct init_mm = INIT_MM;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/time.c linux.ac/arch/alpha/kernel/time.c
--- linux.vanilla/arch/alpha/kernel/time.c Sun Jan 24 19:55:29 1999
+++ linux.ac/arch/alpha/kernel/time.c Wed Feb 24 16:35:19 1999
@@ -95,14 +95,17 @@
/*
* Calculate how many ticks have passed since the last update,
* including any previous partial leftover. Save any resulting
- * fraction for the next pass.
+ * fraction for the next pass. Don't change anything unless
+ * at least one tick has passed.
*/
now = rpcc();
delta = now - state.last_time;
- state.last_time = now;
delta = delta * state.scaled_ticks_per_cycle + state.partial_tick;
- state.partial_tick = delta & ((1UL << FIX_SHIFT) - 1);
nticks = delta >> FIX_SHIFT;
+ if (nticks) {
+ state.last_time = now;
+ state.partial_tick = delta & ((1UL << FIX_SHIFT) - 1);
+ }
while (nticks > 0) {
do_timer(regs);
@@ -316,12 +319,14 @@
{
unsigned long flags, now, delta_cycles, delta_usec;
unsigned long sec, usec;
+ unsigned long partial_tick;
- now = rpcc();
save_and_cli(flags);
+ now = rpcc();
sec = xtime.tv_sec;
usec = xtime.tv_usec;
delta_cycles = now - state.last_time;
+ partial_tick = state.partial_tick;
restore_flags(flags);
/*
@@ -337,7 +342,8 @@
* with no clear gain.
*/
- delta_usec = delta_cycles * state.scaled_ticks_per_cycle * 15625;
+ delta_usec = delta_cycles * state.scaled_ticks_per_cycle + partial_tick;
+ delta_usec *= 15625;
delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2;
usec += delta_usec;
@@ -353,8 +359,24 @@
void
do_settimeofday(struct timeval *tv)
{
+ unsigned long delta_usec;
+
+ /*
+ * The offset that is added into time in do_gettimeofday above must
+ * be subtracted here to keep a coherent view of the time. Without
+ * this, a full-tick error is possible.
+ */
cli();
+ delta_usec = (rpcc() - state.last_time) * state.scaled_ticks_per_cycle +
+ state.partial_tick;
+ delta_usec *= 15625;
+ delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2;
xtime = *tv;
+ xtime.tv_usec -= delta_usec;
+ if (xtime.tv_usec < 0) {
+ xtime.tv_usec += 1000000;
+ xtime.tv_sec--;
+ }
time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC;
time_state = TIME_ERROR; /* p. 24, (a) */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/Makefile linux.ac/arch/arm/Makefile
--- linux.vanilla/arch/arm/Makefile Tue Dec 22 23:19:25 1998
+++ linux.ac/arch/arm/Makefile Sun Feb 28 22:29:39 1999
@@ -10,14 +10,13 @@
# License. See the file "COPYING" in the main directory of this archive
# for more details.
#
-# Copyright (C) 1995, 1996 by Russell King
+# Copyright (C) 1995-1999 by Russell King
CFLAGS_PROC :=
ASFLAGS_PROC :=
-# All processors get `-mshort-load-bytes' for now, to work around alignment
-# problems. This is more of a hack that just happens to work than a real fix
-# but it will do for now.
+# GCC 2.7 uses different options to later compilers; sort out which we have
+CONFIG_BINUTILS_NEW := $(shell if $(CC) --version 2>&1 | grep '^2\.7' > /dev/null; then echo n; else echo y; fi)
ifeq ($(CONFIG_CPU_26),y)
PROCESSOR = armo
@@ -25,6 +24,7 @@
ZTEXTADDR = 0x01800000
ZRELADDR = 0x02080000
ifeq ($(CONFIG_BINUTILS_NEW),y)
+ ELF_ARCH = elf32arm26
CFLAGS_PROC += -mapcs-26 -mshort-load-bytes
ifeq ($(CONFIG_CPU_ARM2),y)
CFLAGS_PROC += -mcpu=arm2
@@ -43,6 +43,7 @@
CFLAGS_PROC += -m3
ASFLAGS_PROC += -m3
endif
+ ELF_ARCH = elf_arm
endif
endif
@@ -50,6 +51,7 @@
PROCESSOR = armv
TEXTADDR = 0xC0008000
ifeq ($(CONFIG_BINUTILS_NEW),y)
+ ELF_ARCH = elf32arm
CFLAGS_PROC += -mapcs-32 -mshort-load-bytes
ifeq ($(CONFIG_CPU_ARM6),y)
CFLAGS_PROC += -mcpu=arm6
@@ -62,16 +64,18 @@
endif
else
CFLAGS_PROC += -m6
+ ELF_ARCH = elf_arm
endif
ASFLAGS_PROC += -m6
endif
# Processor Architecture
# CFLAGS_PROC - processor dependent CFLAGS
-# PROCESSOR - processor type
-# TEXTADDR - Uncompressed kernel link text address
-# ZTEXTADDR - Compressed kernel link text address
-# ZRELADDR - Compressed kernel relocating address (point at which uncompressed kernel is loaded).
+# PROCESSOR - processor type
+# TEXTADDR - Uncompressed kernel link text address
+# ZTEXTADDR - Compressed kernel link text address
+# ZRELADDR - Compressed kernel relocating address
+# (point at which uncompressed kernel is loaded).
#
COMPRESSED_HEAD = head.o
@@ -79,19 +83,16 @@
ifeq ($(CONFIG_ARCH_A5K),y)
MACHINE = a5k
ARCHDIR = arc
-COMPRESSED_EXTRA = $(TOPDIR)/arch/arm/lib/ll_char_wr.o
endif
ifeq ($(CONFIG_ARCH_ARC),y)
MACHINE = arc
ARCHDIR = arc
-COMPRESSED_EXTRA = $(TOPDIR)/arch/arm/lib/ll_char_wr.o
endif
ifeq ($(CONFIG_ARCH_RPC),y)
MACHINE = rpc
ARCHDIR = rpc
-COMPRESSED_EXTRA = $(TOPDIR)/arch/arm/lib/ll_char_wr.o
ZTEXTADDR = 0x10008000
ZRELADDR = 0x10008000
endif
@@ -103,7 +104,7 @@
ZRELADDR = 0x00008000
endif
-ifeq ($(CONFIG_ARCH_EBSA285),y)
+ifeq ($(CONFIG_HOST_FOOTBRIDGE),y)
MACHINE = ebsa285
ARCHDIR = ebsa285
ZTEXTADDR = 0x00008000
@@ -119,31 +120,13 @@
COMPRESSED_HEAD = head-nexuspci.o
endif
-ifeq ($(CONFIG_ARCH_VNC),y)
-TEXTADDR = 0xC000C000
-MACHINE = vnc
-ARCHDIR = vnc
-endif
-
-ifeq ($(CONFIG_ARCH_TBOX),y)
-MACHINE = tbox
-ARCHDIR = tbox
-ZTEXTADDR = 0x80008000
-ZRELDIR = 0x80008000
-endif
-
PERL = perl
-ifeq ($(CONFIG_BINUTILS_NEW),y)
-LD = $(CROSS_COMPILE)ld -m elf32arm
-else
-LD = $(CROSS_COMPILE)ld -m elf_arm
-endif
+LD = $(CROSS_COMPILE)ld -m $(ELF_ARCH)
OBJCOPY = $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
OBJDUMP = $(CROSS_COMPILE)objdump
CPP = $(CC) -E
ARCHCC := $(word 1,$(CC))
GCCLIB := `$(CC) $(CFLAGS_PROC) --print-libgcc-file-name`
-#GCCARCH := -B/usr/bin/arm-linuxelf-
HOSTCFLAGS := $(CFLAGS:-fomit-frame-pointer=)
ifeq ($(CONFIG_FRAME_POINTER),y)
CFLAGS := $(CFLAGS:-fomit-frame-pointer=)
@@ -153,64 +136,32 @@
LINKFLAGS = -T $(TOPDIR)/arch/arm/vmlinux-$(PROCESSOR).lds -e stext -Ttext $(TEXTADDR)
ZLINKFLAGS = -Ttext $(ZTEXTADDR)
-SUBDIRS := $(SUBDIRS:drivers=arch/arm/drivers) arch/arm/lib arch/arm/kernel arch/arm/mm
-HEAD := arch/arm/kernel/head-$(PROCESSOR).o arch/arm/kernel/init_task.o
+# If we're intending to debug the kernel, make sure it has line number
+# information. This gets stripped out when building (z)Image so it doesn't
+# add anything to the footprint of the running kernel.
+ifeq ($(CONFIG_DEBUG_INFO),y)
+CFLAGS += -g
+endif
+
+HEAD := arch/arm/kernel/head-$(PROCESSOR).o \
+ arch/arm/kernel/init_task.o
+SUBDIRS := arch/arm/special $(SUBDIRS) arch/arm/lib arch/arm/kernel \
+ arch/arm/mm arch/arm/nwfpe
CORE_FILES := arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES)
LIBS := arch/arm/lib/lib.a $(LIBS) $(GCCLIB)
-
-BLOCK_DRIVERS := drivers/block/block.a
-CDROM_DRIVERS := drivers/cdrom/cdrom.a
-ifeq ($(CONFIG_FB),y)
-CHAR_DRIVERS := arch/arm/drivers/char1/char1.a drivers/char/char.a arch/arm/drivers/char1/char1.a
-else
-ifeq ($(CONFIG_VGA_CONSOLE),y)
-CHAR_DRIVERS := arch/arm/drivers/char1/char1.a drivers/char/char.a arch/arm/drivers/char1/char1.a
-else
-CHAR_DRIVERS := arch/arm/drivers/char/char.a
-endif
-endif
-MISC_DRIVERS := drivers/misc/misc.a
-NET_DRIVERS := drivers/net/net.a
-PARIDE_DRIVERS := drivers/block/paride/paride.a
-PCI_DRIVERS := drivers/pci/pci.a
-SCSI_DRIVERS := drivers/scsi/scsi.a
-SOUND_DRIVERS := drivers/sound/sound.a
-VIDEO_DRIVERS := drivers/video/video.a
-PNP_DRIVERS := drivers/pnp/pnp.a
+DRIVERS += arch/arm/special/special.a
ifeq ($(CONFIG_ARCH_ACORN),y)
-BLOCK_DRIVERS += drivers/acorn/block/acorn-block.a
-CHAR_DRIVERS += drivers/acorn/char/acorn-char.a
-NET_DRIVERS += drivers/acorn/net/acorn-net.a drivers/net/net.a
-SCSI_DRIVERS += drivers/acorn/scsi/acorn-scsi.a
+SUBDIRS += drivers/acorn/block drivers/acorn/char drivers/acorn/net \
+ drivers/acorn/scsi
+DRIVERS += drivers/acorn/block/acorn-block.a \
+ drivers/acorn/char/acorn-char.a \
+ drivers/acorn/net/acorn-net.a \
+ drivers/acorn/scsi/acorn-scsi.a
endif
-DRIVERS := $(BLOCK_DRIVERS) $(CHAR_DRIVERS) $(MISC_DRIVERS) $(NET_DRIVERS)
-
-ifeq ($(CONFIG_FB),y)
-DRIVERS := $(DRIVERS) $(VIDEO_DRIVERS)
-else
-ifeq ($(CONFIG_VGA_CONSOLE),y)
-DRIVERS := $(DRIVERS) $(VIDEO_DRIVERS)
-endif
-endif
-ifeq ($(CONFIG_SCSI),y)
-DRIVERS := $(DRIVERS) $(SCSI_DRIVERS)
-endif
-ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR),)
-DRIVERS := $(DRIVERS) $(CDROM_DRIVERS)
-endif
-ifdef CONFIG_PCI
-DRIVERS := $(DRIVERS) $(PCI_DRIVERS)
-endif
-ifeq ($(CONFIG_SOUND),y)
-DRIVERS := $(DRIVERS) $(SOUND_DRIVERS)
-endif
-ifeq ($(CONFIG_PARIDE),y)
-DRIVERS := $(DRIVERS) $(PARIDE_DRIVERS)
-endif
-ifdef CONFIG_PNP
-DRIVERS := $(DRIVERS) $(PNP_DRIVERS)
+ifeq ($(CONFIG_NWFPE),y)
+DRIVERS += arch/arm/nwfpe/math-emu.a
endif
symlinks::
@@ -220,7 +171,7 @@
# Once we've finished integrating the sources, the @$(MAKE) will disappear
archmrproper:
rm -f include/asm-arm/arch include/asm-arm/proc
- @$(MAKE) -C arch/$(ARCH)/drivers mrproper
+ @$(MAKE) -C arch/$(ARCH)/special mrproper
arch/arm/kernel: dummy
$(MAKE) linuxsubdirs SUBDIRS=arch/arm/kernel
@@ -257,4 +208,3 @@
archdep:
@$(MAKEBOOT) dep
-sed -e /^MACHINE..*=/s,= .*,= rpc,;/^PROCESSOR..*=/s,= .*,= armv, linux/arch/arm/Makefile.normal
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/boot/compressed/Makefile linux.ac/arch/arm/boot/compressed/Makefile
--- linux.vanilla/arch/arm/boot/compressed/Makefile Sun Nov 8 15:08:42 1998
+++ linux.ac/arch/arm/boot/compressed/Makefile Wed Feb 24 23:48:59 1999
@@ -11,10 +11,15 @@
OBJS =$(HEAD) misc.o $(COMPRESSED_EXTRA)
CFLAGS =-O2 -DSTDC_HEADERS $(CFLAGS_PROC)
ARFLAGS =rc
+FONTC =$(TOPDIR)/drivers/video/font_acorn_8x8.c
+
+ifeq ($(CONFIG_ARCH_ACORN),y)
+OBJS += ll_char_wr.o font.o
+endif
all: vmlinux
-vmlinux: piggy.o $(OBJS)
+vmlinux: $(OBJS) piggy.o
$(LD) $(ZLINKFLAGS) -o vmlinux $(OBJS) piggy.o
$(HEAD): $(HEAD:.o=.S)
@@ -28,6 +33,9 @@
echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \
$(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-arm -T $$tmppiggy.lnk; \
rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk;
+
+font.o: $(FONTC)
+ $(CC) -Dstatic= -c -o $@ $(FONTC)
clean:; rm -f vmlinux core
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/boot/compressed/ll_char_wr.S linux.ac/arch/arm/boot/compressed/ll_char_wr.S
--- linux.vanilla/arch/arm/boot/compressed/ll_char_wr.S Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/boot/compressed/ll_char_wr.S Wed Feb 24 23:49:12 1999
@@ -0,0 +1,158 @@
+/*
+ * linux/arch/arm/lib/ll_char_wr.S
+ *
+ * Copyright (C) 1995, 1996 Russell King.
+ *
+ * Speedups & 1bpp code (C) 1996 Philip Blundell & Russell King.
+ *
+ * 10-04-96 RMK Various cleanups & reduced register usage.
+ * 08-04-98 RMK Shifts re-ordered
+ */
+
+@ Regs: [] = corruptible
+@ {} = used
+@ () = do not use
+#define __ASSEMBLY__
+#include
+#include
+ .text
+
+#define BOLD 0x01
+#define ITALIC 0x02
+#define UNDERLINE 0x04
+#define FLASH 0x08
+#define INVERSE 0x10
+
+LC0: .word SYMBOL_NAME(bytes_per_char_h)
+ .word SYMBOL_NAME(video_size_row)
+ .word SYMBOL_NAME(acorndata_8x8)
+ .word SYMBOL_NAME(con_charconvtable)
+
+ENTRY(ll_write_char)
+ stmfd sp!, {r4 - r7, lr}
+@
+@ Smashable regs: {r0 - r3}, [r4 - r7], (r8 - fp), [ip], (sp), [lr], (pc)
+@
+ eor ip, r1, #UNDERLINE << 9
+/*
+ * calculate colours
+ */
+ tst r1, #INVERSE << 9
+ moveq r2, r1, lsr #16
+ moveq r3, r1, lsr #24
+ movne r2, r1, lsr #24
+ movne r3, r1, lsr #16
+ and r3, r3, #255
+ and r2, r2, #255
+/*
+ * calculate offset into character table
+ */
+ mov r1, r1, lsl #23
+ mov r1, r1, lsr #20
+/*
+ * calculate offset required for each row [maybe I should make this an argument to this fn.
+ * Have to see what the register usage is like in the calling routines.
+ */
+ adr r4, LC0
+ ldmia r4, {r4, r5, r6, lr}
+ ldr r4, [r4]
+ ldr r5, [r5]
+/*
+ * Go to resolution-dependent routine...
+ */
+ cmp r4, #4
+ blt Lrow1bpp
+ eor r2, r3, r2 @ Create eor mask to change colour from bg
+ orr r3, r3, r3, lsl #8 @ to fg.
+ orr r3, r3, r3, lsl #16
+ add r0, r0, r5, lsl #3 @ Move to bottom of character
+ add r1, r1, #7
+ ldrb r7, [r6, r1]
+ tst ip, #UNDERLINE << 9
+ eoreq r7, r7, #255
+ teq r4, #8
+ beq Lrow8bpplp
+@
+@ Smashable regs: {r0 - r3}, [r4], {r5 - r7}, (r8 - fp), [ip], (sp), {lr}, (pc)
+@
+ orr r3, r3, r3, lsl #4
+Lrow4bpplp: ldr r7, [lr, r7, lsl #2]
+ mul r7, r2, r7
+ tst r1, #7 @ avoid using r7 directly after
+ eor ip, r3, r7
+ str ip, [r0, -r5]!
+ LOADREGS(eqfd, sp!, {r4 - r7, pc})
+ sub r1, r1, #1
+ ldrb r7, [r6, r1]
+ ldr r7, [lr, r7, lsl #2]
+ mul r7, r2, r7
+ tst r1, #7 @ avoid using r7 directly after
+ eor ip, r3, r7
+ str ip, [r0, -r5]!
+ subne r1, r1, #1
+ ldrneb r7, [r6, r1]
+ bne Lrow4bpplp
+ LOADREGS(fd, sp!, {r4 - r7, pc})
+
+@
+@ Smashable regs: {r0 - r3}, [r4], {r5 - r7}, (r8 - fp), [ip], (sp), {lr}, (pc)
+@
+Lrow8bpplp: mov ip, r7, lsr #4
+ ldr ip, [lr, ip, lsl #2]
+ mul r4, r2, ip
+ and ip, r7, #15 @ avoid r4
+ ldr ip, [lr, ip, lsl #2] @ avoid r4
+ mul ip, r2, ip @ avoid r4
+ eor r4, r3, r4 @ avoid ip
+ tst r1, #7 @ avoid ip
+ sub r0, r0, r5 @ avoid ip
+ eor ip, r3, ip
+ stmia r0, {r4, ip}
+ LOADREGS(eqfd, sp!, {r4 - r7, pc})
+ sub r1, r1, #1
+ ldrb r7, [r6, r1]
+ mov ip, r7, lsr #4
+ ldr ip, [lr, ip, lsl #2]
+ mul r4, r2, ip
+ and ip, r7, #15 @ avoid r4
+ ldr ip, [lr, ip, lsl #2] @ avoid r4
+ mul ip, r2, ip @ avoid r4
+ eor r4, r3, r4 @ avoid ip
+ tst r1, #7 @ avoid ip
+ sub r0, r0, r5 @ avoid ip
+ eor ip, r3, ip
+ stmia r0, {r4, ip}
+ subne r1, r1, #1
+ ldrneb r7, [r6, r1]
+ bne Lrow8bpplp
+ LOADREGS(fd, sp!, {r4 - r7, pc})
+
+@
+@ Smashable regs: {r0 - r3}, [r4], {r5, r6}, [r7], (r8 - fp), [ip], (sp), [lr], (pc)
+@
+Lrow1bpp: add r6, r6, r1
+ ldmia r6, {r4, r7}
+ tst ip, #INVERSE << 9
+ mvnne r4, r4
+ mvnne r7, r7
+ strb r4, [r0], r5
+ mov r4, r4, lsr #8
+ strb r4, [r0], r5
+ mov r4, r4, lsr #8
+ strb r4, [r0], r5
+ mov r4, r4, lsr #8
+ strb r4, [r0], r5
+ strb r7, [r0], r5
+ mov r7, r7, lsr #8
+ strb r7, [r0], r5
+ mov r7, r7, lsr #8
+ strb r7, [r0], r5
+ mov r7, r7, lsr #8
+ tst ip, #UNDERLINE << 9
+ mvneq r7, r7
+ strb r7, [r0], r5
+ LOADREGS(fd, sp!, {r4 - r7, pc})
+
+ .bss
+ENTRY(con_charconvtable)
+ .space 1024
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/config.in linux.ac/arch/arm/config.in
--- linux.vanilla/arch/arm/config.in Tue Jan 19 02:57:23 1999
+++ linux.ac/arch/arm/config.in Tue Feb 9 21:43:52 1999
@@ -14,18 +14,25 @@
A5000 CONFIG_ARCH_A5K \
RiscPC CONFIG_ARCH_RPC \
EBSA-110 CONFIG_ARCH_EBSA110 \
- EBSA-285 CONFIG_ARCH_EBSA285 \
- NexusPCI CONFIG_ARCH_NEXUSPCI \
- Corel-VNC CONFIG_ARCH_VNC \
- Tbox CONFIG_ARCH_TBOX" RiscPC
+ FootBridge-based CONFIG_FOOTBRIDGE" RiscPC
-if [ "$CONFIG_ARCH_EBSA285" = "y" ]; then
- bool ' Include support for CATS boards' CONFIG_CATS
+if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then
+ bool 'FootBridge in HOST mode' CONFIG_HOST_FOOTBRIDGE
+ if [ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then
+ define_bool CONFIG_ADDIN_FOOTBRIDGE y
+ else
+ define_bool CONFIG_ADDIN_FOOTBRIDGE n
+ fi
+fi
+
+if [ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then
+ bool ' Include support for Intel EBSA285' CONFIG_ARCH_EBSA285
+ bool ' Include support for Chalice CATS boards' CONFIG_CATS
+ bool ' Include support for Corel NetWinder' CONFIG_ARCH_NETWINDER
fi
# Select various configuration options depending on the machine type
# Easy check for Acorn-style architectures
-
if [ "$CONFIG_ARCH_ARC" = "y" -o \
"$CONFIG_ARCH_A5K" = "y" -o \
"$CONFIG_ARCH_RPC" = "y" ]; then
@@ -34,23 +41,19 @@
define_bool CONFIG_ARCH_ACORN n
fi
-if [ "$CONFIG_ARCH_TBOX" = "y" ]; then
- define_bool CONFIG_BUS_I2C y
-fi
+#if [ "$CONFIG_ARCH_TBOX" = "y" ]; then
+# define_bool CONFIG_BUS_I2C y
+#fi
# These machines always have PCI
-
if [ "$CONFIG_ARCH_NEXUSPCI" = "y" -o \
- "$CONFIG_ARCH_VNC" = "y" ]; then
+ "$CONFIG_FOOTBRIDGE" = "y" ]; then
define_bool CONFIG_PCI y
fi
-if [ "$CONFIG_ARCH_EBSA285" = "y" ]; then
- bool "PCI support" CONFIG_PCI
-fi
# These machines have ISA-DMA
if [ "$CONFIG_CATS" = "y" -o \
- "$CONFIG_ARCH_VNC" = "y" ]; then
+ "$CONFIG_ARCH_NETWINDER" = "y" ]; then
define_bool CONFIG_ISA_DMA y
else
define_bool CONFIG_ISA_DMA n
@@ -59,7 +62,6 @@
# Figure out whether this system uses 26-bit or 32-bit CPUs. Nobody has
# ever built a machine that can take both, and now that ARM3 is obsolete
# nobody is likely to either.
-
if [ "$CONFIG_ARCH_ARC" = "y" -o \
"$CONFIG_ARCH_A5K" = "y" ]; then
define_bool CONFIG_CPU_32 n
@@ -71,7 +73,6 @@
# Now allow the user to choose a more precise CPU. This is only used to set
# the flags we pass to GCC, not in any code.
-
choice 'Optimise for CPU' \
"ARM2 CONFIG_CPU_ARM2 \
ARM3 CONFIG_CPU_ARM3 \
@@ -80,22 +81,21 @@
SA110 CONFIG_CPU_SA110" ARM6
if [ "$CONFIG_CPU_26" = "y" ]; then
-
# For 26-bit CPUs, the page size changes with the amount of physical RAM!
# The default is 4MB but if the user has less they have to own up to it here.
-
choice 'Physical memory size' \
"4MB+ CONFIG_PAGESIZE_32 \
- 2MB CONFIG_PAGESIZE_16 \
- 1MB/512K CONFIG_PAGESIZE_8" 4MB+
+ 2MB CONFIG_PAGESIZE_16" 4MB+
fi
endmenu
mainmenu_option next_comment
comment 'Code maturity level options'
bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-bool 'Use new compilation options (for GCC 2.8)' CONFIG_BINUTILS_NEW
-bool 'Compile kernel with frame pointer (for useful debugging)' CONFIG_FRAME_POINTER
+if [ "$CONFIG_CPU_32" = "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then
+ bool 'Enable kernel-mode alignment trap handler (EXPERIMENTAL)' CONFIG_ALIGNMENT_TRAP
+fi
+bool 'Split text into discardable sections' CONFIG_TEXT_SECTIONS
endmenu
mainmenu_option next_comment
@@ -113,13 +113,16 @@
bool 'System V IPC' CONFIG_SYSVIPC
bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
bool 'Sysctl support' CONFIG_SYSCTL
+tristate 'Math emulation' CONFIG_NWFPE
tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
tristate 'Parallel port support' CONFIG_PARPORT
if [ "$CONFIG_PARPORT" != "n" ]; then
- dep_tristate ' Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT
+ if [ "$CONFIG_ARCH_ARC" = "y" ]; then
+ dep_tristate ' Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT
+ fi
dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
# If exactly one hardware type is selected then parport will optimise away
# support for loading any others. Defeat this if the user is keen.
@@ -129,11 +132,23 @@
fi
fi
fi
-if [ "$CONFIG_ARCH_EBSA285" = "y" -o \
- "$CONFIG_ARCH_EBSA110" = "y" -o \
- "$CONFIG_ARCH_VNC" = "y" ]; then
+if [ "$CONFIG_ARCH_EBSA110" = "y" -o \
+ "$CONFIG_ARCH_NETWINDER" = "y" -o \
+ "$CONFIG_CATS" = "y" ]; then
string 'Initial kernel command string' CONFIG_CMDLINE
fi
+if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \
+ "$CONFIG_ARCH_EBSA110" = "y" -o \
+ "$CONFIG_ARCH_EBSA285" = "y" ]; then
+ bool 'Timer and CPU usage LEDs' CONFIG_LEDS
+ if [ "$CONFIG_LEDS" = "y" ]; then
+ if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \
+ "$CONFIG_ARCH_EBSA285" = "y" ]; then
+ bool ' Timer LED' CONFIG_LEDS_TIMER
+ bool ' CPU usage LED' CONFIG_LEDS_CPU
+ fi
+ fi
+fi
endmenu
source drivers/pnp/Config.in
@@ -144,13 +159,15 @@
source drivers/acorn/block/Config.in
fi
-if [ "$CONFIG_VGA_CONSOLE" = "n" -a "$CONFIG_FB" = "n" ]; then
- source arch/arm/drivers/char/Config.in
-else
- source drivers/char/Config.in
-fi
+source drivers/char/Config.in
if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
- source drivers/acorn/char/Config.in
+ if [ "$CONFIG_MOUSE" = "y" ]; then
+ if [ "$CONFIG_ARCH_RPC" != "y" ]; then
+ define_bool CONFIG_KBDMOUSE y
+ else
+ define_bool CONFIG_RPCMOUSE y
+ fi
+ fi
fi
if [ "$CONFIG_VT" = "y" ]; then
@@ -166,9 +183,11 @@
if [ "$CONFIG_NET" = "y" ]; then
source net/Config.in
-fi
-if [ "$CONFIG_NET" = "y" ]; then
+ source net/ax25/Config.in
+
+ source net/irda/Config.in
+
mainmenu_option next_comment
comment 'Network device support'
@@ -179,6 +198,15 @@
endmenu
fi
+# mainmenu_option next_comment
+# comment 'ISDN subsystem'
+#
+# tristate 'ISDN support' CONFIG_ISDN
+# if [ "$CONFIG_ISDN" != "n" ]; then
+# source drivers/isdn/Config.in
+# fi
+# endmenu
+
mainmenu_option next_comment
comment 'SCSI support'
@@ -200,21 +228,21 @@
endmenu
fi
-# mainmenu_option next_comment
-# comment 'ISDN subsystem'
-#
-# tristate 'ISDN support' CONFIG_ISDN
-# if [ "$CONFIG_ISDN" != "n" ]; then
-# source drivers/isdn/Config.in
-# fi
-# endmenu
-
source fs/Config.in
mainmenu_option next_comment
comment 'Kernel hacking'
-bool 'Debug kernel errors' CONFIG_DEBUG_ERRORS
+bool 'Compile kernel with frame pointer (for useful debugging)' CONFIG_FRAME_POINTER
+bool 'Verbose kernel error messages' CONFIG_DEBUG_ERRORS
+bool 'Verbose user fault messages' CONFIG_DEBUG_USER
+bool 'Include debugging information in kernel binary' CONFIG_DEBUG_INFO
#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+if [ "$CONFIG_CPU_26" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool 'Disable pgtable cache (EXPERIMENTAL)' CONFIG_NO_PGT_CACHE
+fi
+if [ "$CONFIG_CPU_32" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate 'RISC OS personality' CONFIG_ARTHUR
+fi
endmenu
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/defconfig linux.ac/arch/arm/defconfig
--- linux.vanilla/arch/arm/defconfig Sun Nov 8 15:08:43 1998
+++ linux.ac/arch/arm/defconfig Thu Feb 25 22:38:32 1999
@@ -4,47 +4,70 @@
CONFIG_ARM=y
#
+# System and processor type
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_EBSA110 is not set
+CONFIG_FOOTBRIDGE=y
+CONFIG_HOST_FOOTBRIDGE=y
+CONFIG_ADDIN_FOOTBRIDGE=y
+CONFIG_ARCH_EBSA285=y
+# CONFIG_CATS is not set
+CONFIG_ARCH_NETWINDER=y
+# CONFIG_ARCH_ACORN is not set
+CONFIG_PCI=y
+CONFIG_ISA_DMA=y
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+# CONFIG_CPU_ARM2 is not set
+# CONFIG_CPU_ARM3 is not set
+# CONFIG_CPU_ARM6 is not set
+# CONFIG_CPU_ARM7 is not set
+CONFIG_CPU_SA110=y
+
+#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
+# CONFIG_ALIGNMENT_TRAP is not set
+# CONFIG_TEXT_SECTIONS is not set
#
# Loadable module support
#
CONFIG_MODULES=y
-CONFIG_MODVERSIONS=y
+# CONFIG_MODVERSIONS is not set
CONFIG_KMOD=y
#
# General setup
#
-# CONFIG_ARCH_ARC is not set
-# CONFIG_ARCH_A5K is not set
-CONFIG_ARCH_RPC=y
-# CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_NEXUSPCI is not set
-CONFIG_ARCH_ACORN=y
-# CONFIG_PCI is not set
-# CONFIG_CPU_ARM2 is not set
-# CONFIG_CPU_ARM3 is not set
-# CONFIG_CPU_ARM6 is not set
-CONFIG_CPU_SA110=y
-CONFIG_FRAME_POINTER=y
-# CONFIG_BINUTILS_NEW is not set
-CONFIG_DEBUG_ERRORS=y
CONFIG_NET=y
CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
+CONFIG_NWFPE=y
CONFIG_BINFMT_AOUT=y
-CONFIG_BINFMT_ELF=m
-# CONFIG_BINFMT_JAVA is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
CONFIG_PARPORT=y
CONFIG_PARPORT_PC=y
+CONFIG_CMDLINE="root=/dev/hda1 ro mem=32M parport=0x378,23 ide0=autotune"
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+# CONFIG_LEDS_CPU is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
#
-# Floppy, IDE, and other block devices
+# Block devices
#
-CONFIG_BLK_DEV_FD=y
+# CONFIG_BLK_DEV_FD is not set
CONFIG_BLK_DEV_IDE=y
#
@@ -52,47 +75,177 @@
#
# CONFIG_BLK_DEV_HD_IDE is not set
CONFIG_BLK_DEV_IDEDISK=y
-CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDECD is not set
# CONFIG_BLK_DEV_IDETAPE is not set
# CONFIG_BLK_DEV_IDEFLOPPY is not set
# CONFIG_BLK_DEV_IDESCSI is not set
-# CONFIG_BLK_DEV_IDE_PCMCIA is not set
-CONFIG_BLK_DEV_IDE_CARDS=y
-CONFIG_BLK_DEV_IDE_ICSIDE=y
-# CONFIG_BLK_DEV_IDE_RAPIDE is not set
-# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_IDEDMA=y
+CONFIG_BLK_DEV_OFFBOARD=y
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_VIA82C586 is not set
+# CONFIG_BLK_DEV_CMD646 is not set
+CONFIG_BLK_DEV_SL82C105=y
+# CONFIG_IDE_CHIPSETS is not set
#
# Additional Block Devices
#
CONFIG_BLK_DEV_LOOP=m
-# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_STRIPED=m
+CONFIG_MD_MIRRORING=m
+CONFIG_MD_RAID5=m
CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_DEV_XD is not set
CONFIG_PARIDE_PARPORT=y
-# CONFIG_PARIDE is not set
-CONFIG_BLK_DEV_PART=y
+CONFIG_PARIDE=m
+
+#
+# Parallel IDE high-level drivers
+#
+CONFIG_PARIDE_PD=m
+CONFIG_PARIDE_PCD=m
+CONFIG_PARIDE_PF=m
+CONFIG_PARIDE_PT=m
+CONFIG_PARIDE_PG=m
+
+#
+# Parallel IDE protocol modules
+#
+CONFIG_PARIDE_ATEN=m
+CONFIG_PARIDE_BPCK=m
+CONFIG_PARIDE_COMM=m
+CONFIG_PARIDE_DSTR=m
+CONFIG_PARIDE_FIT2=m
+CONFIG_PARIDE_FIT3=m
+CONFIG_PARIDE_EPAT=m
+CONFIG_PARIDE_EPIA=m
+CONFIG_PARIDE_FRIQ=m
+CONFIG_PARIDE_FRPW=m
+CONFIG_PARIDE_KBIC=m
+CONFIG_PARIDE_KTTI=m
+CONFIG_PARIDE_ON20=m
+CONFIG_PARIDE_ON26=m
# CONFIG_BLK_DEV_HD is not set
#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_UNIX98_PTYS is not set
+CONFIG_PRINTER=m
+CONFIG_PRINTER_READBACK=y
+CONFIG_MOUSE=y
+
+#
+# Mice
+#
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_QIC02_TAPE is not set
+CONFIG_WATCHDOG=y
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+# CONFIG_WDT is not set
+CONFIG_SOFT_WATCHDOG=y
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_ACQUIRE_WDT is not set
+CONFIG_DS1620=y
+CONFIG_NWBUTTON=y
+CONFIG_NWBUTTON_REBOOT=y
+# CONFIG_NVRAM is not set
+CONFIG_RTC=y
+
+#
+# Video For Linux
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Joystick support
+#
+# CONFIG_JOYSTICK is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+
+#
+# Console drivers
+#
+CONFIG_VGA_CONSOLE=y
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FB_CYBER2000=y
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FBCON_ADVANCED=y
+# CONFIG_FBCON_MFB is not set
+# CONFIG_FBCON_CFB2 is not set
+# CONFIG_FBCON_CFB4 is not set
+CONFIG_FBCON_CFB8=y
+CONFIG_FBCON_CFB16=y
+CONFIG_FBCON_CFB24=y
+# CONFIG_FBCON_CFB32 is not set
+# CONFIG_FBCON_AFB is not set
+# CONFIG_FBCON_ILBM is not set
+# CONFIG_FBCON_IPLAN2P2 is not set
+# CONFIG_FBCON_IPLAN2P4 is not set
+# CONFIG_FBCON_IPLAN2P8 is not set
+# CONFIG_FBCON_MAC is not set
+CONFIG_FBCON_VGA=y
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+CONFIG_FBCON_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+CONFIG_FONT_ACORN_8x8=y
+
+#
# Networking options
#
-# CONFIG_PACKET is not set
+CONFIG_PACKET=y
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
-# CONFIG_NET_ALIAS is not set
+CONFIG_NET_ALIAS=y
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_IP_ACCT is not set
-# CONFIG_IP_MASQUERADE is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_ALIAS is not set
+CONFIG_IP_ALIAS=y
# CONFIG_SYN_COOKIES is not set
#
@@ -100,7 +253,7 @@
#
# CONFIG_INET_RARP is not set
CONFIG_IP_NOSR=y
-# CONFIG_SKB_LARGE is not set
+CONFIG_SKB_LARGE=y
# CONFIG_IPV6 is not set
#
@@ -112,155 +265,227 @@
# CONFIG_LAPB is not set
# CONFIG_BRIDGE is not set
# CONFIG_LLC is not set
+# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_FASTROUTE is not set
# CONFIG_NET_HW_FLOWCONTROL is not set
# CONFIG_CPU_IS_SLOW is not set
+
+#
+# QoS and/or fair queueing
+#
# CONFIG_NET_SCHED is not set
-# CONFIG_NET_PROFILE is not set
#
-# SCSI support
+# Amateur Radio support
#
-CONFIG_SCSI=y
+# CONFIG_HAMRADIO is not set
#
-# SCSI support type (disk, tape, CD-ROM)
+# IrDA subsystem support
#
-CONFIG_BLK_DEV_SD=y
-# CONFIG_CHR_DEV_ST is not set
-CONFIG_BLK_DEV_SR=y
-# CONFIG_BLK_DEV_SR_VENDOR is not set
-# CONFIG_CHR_DEV_SG is not set
+# CONFIG_IRDA is not set
#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+# Network device support
#
-# CONFIG_SCSI_MULTI_LUN is not set
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_ARM_AM79C961A is not set
+CONFIG_NET_VENDOR_3COM=y
+# CONFIG_EL1 is not set
+# CONFIG_EL2 is not set
+# CONFIG_ELPLUS is not set
+# CONFIG_EL16 is not set
+# CONFIG_EL3 is not set
+# CONFIG_3C515 is not set
+CONFIG_VORTEX=y
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_RTL8139 is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_EISA=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_DE4X5 is not set
+CONFIG_DEC_ELCP=m
+# CONFIG_DGRS is not set
+# CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_LNE390 is not set
+# CONFIG_NE3210 is not set
+CONFIG_NE2K_PCI=y
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_ES3210 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_ZNET is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_DLCI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
#
-# SCSI low-level drivers
+# CCP compressors for PPP are only built as modules.
#
-CONFIG_SCSI_ACORNSCSI_3=m
-CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE=y
-CONFIG_SCSI_ACORNSCSI_SYNC=y
-CONFIG_SCSI_CUMANA_2=m
-CONFIG_SCSI_POWERTECSCSI=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_NET_RADIO is not set
+# CONFIG_TR is not set
+# CONFIG_SHAPER is not set
+# CONFIG_HOSTESS_SV11 is not set
+# CONFIG_COSA is not set
+# CONFIG_RCPCI is not set
#
-# The following drives are not fully supported
+# SCSI support
#
-CONFIG_SCSI_CUMANA_1=m
-CONFIG_SCSI_OAK1=m
-CONFIG_SCSI_PPA=m
-CONFIG_SCSI_PPA_HAVE_PEDANTIC=2
+# CONFIG_SCSI is not set
#
-# Network device support
+# Sound
#
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_EQUALIZER is not set
-CONFIG_PPP=m
+CONFIG_SOUND=m
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+CONFIG_SOUND_OSS=m
+# CONFIG_SOUND_PAS is not set
+# CONFIG_SOUND_SB is not set
+CONFIG_SOUND_ADLIB=m
+# CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_MPU401 is not set
+# CONFIG_SOUND_PSS is not set
+# CONFIG_SOUND_MSS is not set
+# CONFIG_SOUND_SSCAPE is not set
+# CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_MAD16 is not set
+# CONFIG_SOUND_WAVEFRONT is not set
+# CONFIG_SOUND_CS4232 is not set
+CONFIG_SOUND_OPL3SA2=m
+# CONFIG_SOUND_MAUI is not set
+# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_OPL3SA1 is not set
+# CONFIG_SOUND_SOFTOSS is not set
+# CONFIG_SOUND_YM3812 is not set
+# CONFIG_SOUND_VMIDI is not set
+# CONFIG_SOUND_UART6850 is not set
+# CONFIG_SOUND_VIDC is not set
+CONFIG_SOUND_WAVEARTIST=m
+CONFIG_WAVEARTIST_BASE=250
+CONFIG_WAVEARTIST_IRQ=28
+CONFIG_WAVEARTIST_DMA=5
+CONFIG_WAVEARTIST_DMA2=9
#
-# CCP compressors for PPP are only built as modules.
+# Additional low level sound drivers
#
-# CONFIG_SLIP is not set
-CONFIG_ETHER1=m
-CONFIG_ETHER3=m
-CONFIG_ETHERH=m
+# CONFIG_LOWLEVEL_SOUND is not set
#
# Filesystems
#
# CONFIG_QUOTA is not set
-# CONFIG_MINIX_FS is not set
-CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
-CONFIG_JOLIET=y
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
-CONFIG_PROC_FS=y
-CONFIG_NFS_FS=y
-CONFIG_NFSD=y
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-# CONFIG_CODA_FS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_SYSV_FS is not set
+# CONFIG_AUTOFS_FS is not set
+CONFIG_ADFS_FS=y
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=m
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_QNX4FS_FS is not set
# CONFIG_ROMFS_FS is not set
-# CONFIG_AUTOFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
-CONFIG_ADFS_FS=y
-CONFIG_ADFS_FS=y
-# CONFIG_MAC_PARTITION is not set
-CONFIG_NLS=y
#
-# Native Language Support
+# Network File Systems
#
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_KOI8_R is not set
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=m
+# CONFIG_NFSD_SUN is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
#
-# Character devices
+# Partition Types
#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-# CONFIG_SERIAL_EXTENDED is not set
-CONFIG_ATOMWIDE_SERIAL=y
-CONFIG_DUALSP_SERIAL=y
-CONFIG_MOUSE=y
-CONFIG_PRINTER=m
-CONFIG_PRINTER_READBACK=y
-# CONFIG_UMISC is not set
-# CONFIG_WATCHDOG is not set
-CONFIG_RPCMOUSE=y
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+CONFIG_ACORN_PARTITION=y
+CONFIG_ACORN_PARTITION_ADFS=y
+# CONFIG_ACORN_PARTITION_ICS is not set
+# CONFIG_ACORN_PARTITION_POWERTEC is not set
+# CONFIG_ACORN_PARTITION_RISCIX is not set
+CONFIG_NLS=y
#
-# Sound
+# Native Language Support
#
-CONFIG_SOUND=m
-CONFIG_VIDC=y
-CONFIG_AUDIO=y
-DSP_BUFFSIZE=65536
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_ISO8859_9=m
+# CONFIG_NLS_ISO8859_15 is not set
+CONFIG_NLS_KOI8_R=m
#
# Kernel hacking
#
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_INFO is not set
CONFIG_MAGIC_SYSRQ=y
+# CONFIG_ARTHUR is not set
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/Makefile linux.ac/arch/arm/kernel/Makefile
--- linux.vanilla/arch/arm/kernel/Makefile Tue Dec 22 23:19:26 1998
+++ linux.ac/arch/arm/kernel/Makefile Tue Jan 26 21:58:36 1999
@@ -9,31 +9,39 @@
ENTRY_OBJ = entry-$(PROCESSOR).o
O_TARGET := kernel.o
-O_OBJS := $(ENTRY_OBJ) ioport.o irq.o process.o ptrace.o setup.o \
+O_OBJS := $(ENTRY_OBJ) irq.o process.o ptrace.o setup.o \
signal.o sys_arm.o time.o traps.o
-DMA_OBJS_arc = dma-arc.o
-DMA_OBJS_a5k = dma-a5k.o
-DMA_OBJS_rpc = dma-rpc.o
-DMA_OBJS_ebsa110 = dma-dummy.o
-DMA_OBJS_ebsa285 = dma-ebsa285.o
-DMA_OBJS_nexuspci =
-DMA_OBJS_vnc = dma-vnc.o
-
-O_OBJS_arc = ecard.o iic.o fiq.o oldlatches.o
-O_OBJS_a5k = ecard.o iic.o fiq.o
-O_OBJS_rpc = ecard.o iic.o fiq.o
-O_OBJS_ebsa110 = leds-ebsa110.o
-O_OBJS_ebsa285 = leds-ebsa285.o hw-ebsa285.o
-O_OBJS_nexuspci =
-O_OBJS_vnc = leds-ebsa285.o hw-vnc.o
+ifeq ($(CONFIG_ISA_DMA),y)
+ ISA_DMA_OBJS += dma-isa.o
+endif
+
+O_OBJS_arc = dma-arc.o iic.o fiq.o oldlatches.o
+O_OBJS_a5k = dma-a5k.o iic.o fiq.o
+O_OBJS_rpc = dma-rpc.o iic.o fiq.o
+O_OBJS_ebsa110 = dma-dummy.o
+O_OBJS_ebsa285 = dma-ebsa285.o $(ISA_DMA_OBJS)
+O_OBJS_nexuspci = dma-dummy.o
+O_OBJS_co285 = dma-ebsa285.o $(ISA_DMA_OBJS)
+
+OX_OBJS_arc = dma.o
+OX_OBJS_a5k = dma.o
+OX_OBJS_rpc = dma.o
+OX_OBJS_ebsa110 =
+OX_OBJS_ebsa285 = dma.o hw-ebsa285.o
+OX_OBJS_nexuspci =
+OX_OBJS_co285 = dma.o
all: lib kernel.o $(HEAD_OBJ) init_task.o
+O_OBJS += $(O_OBJS_$(MACHINE))
+
ifeq ($(CONFIG_MODULES),y)
OX_OBJS = armksyms.o
-else
- O_OBJS += armksyms.o
+endif
+
+ifeq ($(CONFIG_ARCH_ACORN),y)
+ OX_OBJS += ecard.o
endif
ifeq ($(MACHINE),nexuspci)
@@ -46,17 +54,23 @@
endif
endif
-ifneq ($(DMA_OBJS_$(MACHINE)),)
- OX_OBJS += dma.o
- O_OBJS += $(DMA_OBJS_$(MACHINE))
- ifeq ($(CONFIG_ISA_DMA),y)
- O_OBJS += dma-isa.o
- endif
+ifdef CONFIG_LEDS
+ O_OBJS += leds-$(MACHINE).o
+endif
+
+ifeq ($(CONFIG_MODULES),y)
+ OX_OBJS += $(OX_OBJS_$(MACHINE))
else
- O_OBJS += dma-dummy.o
+ O_OBJS += $(OX_OBJS_$(MACHINE))
endif
-O_OBJS += $(O_OBJS_$(MACHINE))
+ifeq ($(CONFIG_ARTHUR),y)
+ O_OBJS += arthur.o
+else
+ ifeq ($(CONFIG_ARTHUR),m)
+ M_OBJS += arthur.o
+ endif
+endif
$(HEAD_OBJ): $(HEAD_OBJ:.o=.S)
$(CC) -D__ASSEMBLY__ -DTEXTADDR=$(TEXTADDR) -traditional -c $(HEAD_OBJ:.o=.S) -o $@
@@ -72,3 +86,7 @@
lib:
$(MAKE) -C ../lib constants.h
+
+# Spell out some dependencies that `make dep' doesn't spot
+entry-armv.o: calls.S
+entry-armo.o: calls.S
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/armksyms.c linux.ac/arch/arm/kernel/armksyms.c
--- linux.vanilla/arch/arm/kernel/armksyms.c Sun Nov 8 15:08:43 1998
+++ linux.ac/arch/arm/kernel/armksyms.c Sun Feb 28 15:21:17 1999
@@ -7,11 +7,11 @@
#include
#include
-#include
#include
#include
#include
#include
+#include
#include
#include
@@ -20,6 +20,19 @@
extern void inswb(unsigned int port, void *to, int len);
extern void outswb(unsigned int port, const void *to, int len);
+extern unsigned int local_bh_count[NR_CPUS];
+extern unsigned int local_irq_count[NR_CPUS];
+
+/*
+ * syscalls
+ */
+extern int sys_write(int, const char *, int);
+extern int sys_read(int, char *, int);
+extern int sys_lseek(int, off_t, int);
+extern int sys_open(const char *, int, int);
+extern int sys_exit(int);
+extern int sys_wait4(int, int *, int, struct rusage *);
+
/*
* libgcc functions - functions that are used internally by the
* compiler... (prototypes are not correct though, but that
@@ -43,6 +56,8 @@
extern void __umoddi3(void);
extern void __umodsi3(void);
+extern void ret_from_exception(void);
+extern void fpundefinstr(void);
extern void fp_enter(void);
#define EXPORT_SYMBOL_ALIAS(sym,orig) \
const char __kstrtab_##sym##[] __attribute__((section(".kstrtab"))) = \
@@ -57,19 +72,18 @@
EXPORT_SYMBOL_ALIAS(fp_printk,printk);
EXPORT_SYMBOL_ALIAS(fp_send_sig,send_sig);
+#ifdef CONFIG_CPU_26
+EXPORT_SYMBOL(fpundefinstr);
+EXPORT_SYMBOL(ret_from_exception);
+#endif
+
/* platform dependent support */
EXPORT_SYMBOL(dump_thread);
EXPORT_SYMBOL(dump_fpu);
EXPORT_SYMBOL(udelay);
EXPORT_SYMBOL(xchg_str);
-
- /* expansion card support */
-#ifdef CONFIG_ARCH_ACORN
-EXPORT_SYMBOL(ecard_startfind);
-EXPORT_SYMBOL(ecard_find);
-EXPORT_SYMBOL(ecard_readchunk);
-EXPORT_SYMBOL(ecard_address);
-#endif
+EXPORT_SYMBOL(local_bh_count);
+EXPORT_SYMBOL(local_irq_count);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
@@ -79,10 +93,12 @@
EXPORT_SYMBOL(machine_type);
/* io */
-EXPORT_SYMBOL(outswb);
+EXPORT_SYMBOL(outsb);
EXPORT_SYMBOL(outsw);
-EXPORT_SYMBOL(inswb);
+EXPORT_SYMBOL(outsl);
+EXPORT_SYMBOL(insb);
EXPORT_SYMBOL(insw);
+EXPORT_SYMBOL(insl);
/* address translation */
#ifndef __virt_to_phys__is_a_macro
@@ -98,7 +114,9 @@
EXPORT_SYMBOL(__bus_to_virt);
#endif
+#ifndef CONFIG_NO_PGT_CACHE
EXPORT_SYMBOL(quicklists);
+#endif
EXPORT_SYMBOL(__bad_pmd);
EXPORT_SYMBOL(__bad_pmd_kernel);
@@ -167,3 +185,17 @@
EXPORT_SYMBOL(armidlist);
EXPORT_SYMBOL(armidindex);
EXPORT_SYMBOL(elf_platform);
+
+ /* syscalls */
+EXPORT_SYMBOL(sys_write);
+EXPORT_SYMBOL(sys_read);
+EXPORT_SYMBOL(sys_lseek);
+EXPORT_SYMBOL(sys_open);
+EXPORT_SYMBOL(sys_exit);
+EXPORT_SYMBOL(sys_wait4);
+
+ /* semaphores */
+EXPORT_SYMBOL_NOVERS(__down_failed);
+EXPORT_SYMBOL_NOVERS(__down_interruptible_failed);
+EXPORT_SYMBOL_NOVERS(__up_wakeup);
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/arthur.c linux.ac/arch/arm/kernel/arthur.c
--- linux.vanilla/arch/arm/kernel/arthur.c Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/kernel/arthur.c Sun Jan 3 10:05:59 1999
@@ -0,0 +1,88 @@
+/*
+ * Arthur personality
+ * Copyright (C) 1998 Philip Blundell
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+/* RISC OS doesn't have many signals, and a lot of those that it does
+ have don't map easily to any Linux equivalent. Never mind. */
+
+#define RISCOS_SIGABRT 1
+#define RISCOS_SIGFPE 2
+#define RISCOS_SIGILL 3
+#define RISCOS_SIGINT 4
+#define RISCOS_SIGSEGV 5
+#define RISCOS_SIGTERM 6
+#define RISCOS_SIGSTAK 7
+#define RISCOS_SIGUSR1 8
+#define RISCOS_SIGUSR2 9
+#define RISCOS_SIGOSERROR 10
+
+static unsigned long riscos_to_linux_signals[32] = {
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31
+};
+
+static unsigned long linux_to_riscos_signals[32] = {
+ 0, -1, RISCOS_SIGINT, -1,
+ RISCOS_SIGILL, 5, RISCOS_SIGABRT, 7,
+ RISCOS_SIGFPE, 9, RISCOS_SIGUSR1, RISCOS_SIGSEGV,
+ RISCOS_SIGUSR2, 13, 14, RISCOS_SIGTERM,
+ 16, 17, 18, 19,
+ 20, 21, 22, 23,
+ 24, 25, 26, 27,
+ 28, 29, 30, 31
+};
+
+static void arthur_lcall7(int nr, struct pt_regs *regs)
+{
+ struct siginfo info;
+ info.si_signo = SIGSWI;
+ info.si_code = nr;
+ /* Bounce it to the emulator */
+ send_sig_info(SIGSWI, &info, current);
+}
+
+static struct exec_domain riscos_exec_domain = {
+ "Arthur", /* name */
+ (lcall7_func)arthur_lcall7,
+ PER_RISCOS, PER_RISCOS,
+ riscos_to_linux_signals,
+ linux_to_riscos_signals,
+#ifdef MODULE
+ &__this_module, /* No usage counter. */
+#else
+ NULL,
+#endif
+ NULL /* Nothing after this in the list. */
+};
+
+/*
+ * We could do with some locking to stop Arthur being removed while
+ * processes are using it.
+ */
+
+#ifdef MODULE
+int init_module(void)
+#else
+int initialise_arthur(void)
+#endif
+{
+ return register_exec_domain(&riscos_exec_domain);
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+ unregister_exec_domain(&riscos_exec_domain);
+}
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/calls.S linux.ac/arch/arm/kernel/calls.S
--- linux.vanilla/arch/arm/kernel/calls.S Tue Dec 22 23:19:26 1998
+++ linux.ac/arch/arm/kernel/calls.S Mon Jan 18 23:01:57 1999
@@ -110,7 +110,7 @@
.long SYMBOL_NAME(sys_ni_syscall) /* was sys_profil */
.long SYMBOL_NAME(sys_statfs)
/* 100 */ .long SYMBOL_NAME(sys_fstatfs)
- .long SYMBOL_NAME(sys_ni_syscall) /* .long _sys_ioperm */
+ .long SYMBOL_NAME(sys_ni_syscall)
.long SYMBOL_NAME(sys_socketcall)
.long SYMBOL_NAME(sys_syslog)
.long SYMBOL_NAME(sys_setitimer)
@@ -119,7 +119,7 @@
.long SYMBOL_NAME(sys_newlstat)
.long SYMBOL_NAME(sys_newfstat)
.long SYMBOL_NAME(sys_uname)
-/* 110 */ .long SYMBOL_NAME(sys_iopl)
+/* 110 */ .long SYMBOL_NAME(sys_ni_syscall)
.long SYMBOL_NAME(sys_vhangup)
.long SYMBOL_NAME(sys_idle)
.long SYMBOL_NAME(sys_syscall) /* call a syscall */
@@ -196,6 +196,10 @@
.long SYMBOL_NAME(sys_capget)
/* 185 */ .long SYMBOL_NAME(sys_capset)
.long SYMBOL_NAME(sys_sigaltstack_wrapper)
+ .long SYMBOL_NAME(sys_sendfile)
+ .long SYMBOL_NAME(sys_ni_syscall)
+ .long SYMBOL_NAME(sys_ni_syscall)
+/* 190 */ .long SYMBOL_NAME(sys_vfork_wrapper)
.rept NR_syscalls-186
.long SYMBOL_NAME(sys_ni_syscall)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/dec21285.c linux.ac/arch/arm/kernel/dec21285.c
--- linux.vanilla/arch/arm/kernel/dec21285.c Tue Dec 22 23:19:26 1998
+++ linux.ac/arch/arm/kernel/dec21285.c Fri Jan 22 09:06:54 1999
@@ -17,8 +17,6 @@
extern void pcibios_fixup_ebsa285(struct pci_dev *dev);
extern void pcibios_init_ebsa285(void);
-extern void pcibios_fixup_vnc(struct pci_dev *dev);
-extern void pcibios_init_vnc(void);
int
pcibios_present(void)
@@ -151,10 +149,7 @@
struct pci_dev *dev;
for (dev = pci_devices; dev; dev = dev->next) {
- if (machine_is_ebsa285() || machine_is_cats())
- pcibios_fixup_ebsa285(dev);
- if (machine_is_netwinder())
- pcibios_fixup_vnc(dev);
+ pcibios_fixup_ebsa285(dev);
pcibios_write_config_byte(dev->bus->number, dev->devfn,
PCI_INTERRUPT_LINE, dev->irq);
@@ -164,18 +159,18 @@
dev->bus->number, dev->devfn,
dev->vendor, dev->device, dev->irq);
}
+ /*
+ * this ought to have a better home
+ */
if (machine_is_netwinder())
hw_init();
}
__initfunc(void pcibios_init(void))
{
- if (machine_is_ebsa285() || machine_is_cats())
- pcibios_init_ebsa285();
- if (machine_is_netwinder())
- pcibios_init_vnc();
+ pcibios_init_ebsa285();
- printk("DEC21285 PCI revision %02X\n", *(unsigned char *)0xfe000008);
+ printk(KERN_DEBUG "PCI: DEC21285 revision %02X\n", *(unsigned char *)0xfe000008);
}
__initfunc(void pcibios_fixup_bus(struct pci_bus *bus))
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/dma-a5k.c linux.ac/arch/arm/kernel/dma-a5k.c
--- linux.vanilla/arch/arm/kernel/dma-a5k.c Tue Dec 22 23:19:26 1998
+++ linux.ac/arch/arm/kernel/dma-a5k.c Tue Feb 2 20:31:32 1999
@@ -37,8 +37,9 @@
if (channel != DMA_VIRTUAL_FLOPPY)
printk("arch_dma_count: invalid channel %d\n", channel);
else {
- extern int floppy_fiqresidual(void);
- return floppy_fiqresidual();
+ struct pt_regs regs;
+ get_fiq_regs(®s);
+ return regs.ARM_r9;
}
return 0;
}
@@ -48,6 +49,7 @@
if (channel != DMA_VIRTUAL_FLOPPY)
printk("arch_enable_dma: invalid channel %d\n", channel);
else {
+ struct pt_regs regs;
void *fiqhandler_start;
unsigned int fiqhandler_length;
extern void floppy_fiqsetup(unsigned long len, unsigned long addr,
@@ -67,8 +69,10 @@
return;
}
memcpy((void *)0x1c, fiqhandler_start, fiqhandler_length);
- flush_page_to_ram(0);
- floppy_fiqsetup(dma->buf.length, __bus_to_virt(dma->buf.address), (int)PCIO_FLOPPYDMABASE);
+ regs.ARM_r9 = dma->buf.length;
+ regs.ARM_r10 = __bus_to_virt(dma->buf.address);
+ regs.ARM_fp = (int)PCIO_FLOPPYDMABASE;
+ set_fiq_regs(®s);
enable_irq(dma->dma_irq);
}
}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/dma-arc.c linux.ac/arch/arm/kernel/dma-arc.c
--- linux.vanilla/arch/arm/kernel/dma-arc.c Sun Nov 8 15:08:43 1998
+++ linux.ac/arch/arm/kernel/dma-arc.c Tue Feb 2 20:17:01 1999
@@ -1,10 +1,11 @@
/*
* arch/arm/kernel/dma-arc.c
*
- * Copyright (C) 1998 Dave Gilbert / Russell King
+ * Copyright (C) 1998-1999 Dave Gilbert / Russell King
*
* DMA functions specific to Archimedes architecture
*/
+#include
#include
#include
@@ -14,7 +15,7 @@
#include "dma.h"
-int arch_request_dma(dmach_t channel, dma_t *dma)
+int arch_request_dma(dmach_t channel, dma_t *dma, const char * dev_id)
{
if (channel == DMA_VIRTUAL_FLOPPY0 ||
channel == DMA_VIRTUAL_FLOPPY1)
@@ -25,16 +26,12 @@
void arch_free_dma(dmach_t channel, dma_t *dma)
{
- if (channel != DMA_VIRTUAL_FLOPPY0 &&
- channel != DMA_VIRTUAL_FLOPPY1)
- return 0;
- else
- return -EINVAL;
}
void arch_enable_dma(dmach_t channel, dma_t *dma)
{
switch (channel) {
+#ifdef CONFIG_BLK_DEV_FD
case DMA_VIRTUAL_FLOPPY0: { /* Data DMA */
switch (dma->dma_mode) {
case DMA_MODE_READ: /* read */
@@ -96,7 +93,36 @@
restore_flags(flags);
}
break;
+#endif
}
+}
+
+int arch_get_dma_residue(dmach_t channel, dma_t *dma)
+{
+ switch (channel) {
+#ifdef CONFIG_BLK_DEV_FD
+ case DMA_VIRTUAL_FLOPPY0: { /* Data DMA */
+ extern unsigned int fdc1772_bytestogo;
+
+ /* 10/1/1999 DAG - I presume its the number of bytes left? */
+ return fdc1772_bytestogo;
+ };
+ break;
+
+ case DMA_VIRTUAL_FLOPPY1: { /* Command completed */
+ /* 10/1/1999 DAG - Presume whether there is an outstanding command? */
+ extern unsigned int fdc1772_fdc_int_done;
+
+ return (fdc1772_fdc_int_done==0)?1:0; /* Explicit! If the int done is 0 then 1 int to go */
+ };
+ break;
+
+#endif
+
+ default:
+ printk("dma-arc.c:arch_get_dma_residue called with unknown/unconfigured DMA channel\n");
+ return 0;
+ };
}
void arch_disable_dma(dmach_t channel, dma_t *dma)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/dma-dummy.c linux.ac/arch/arm/kernel/dma-dummy.c
--- linux.vanilla/arch/arm/kernel/dma-dummy.c Sun Nov 8 15:08:43 1998
+++ linux.ac/arch/arm/kernel/dma-dummy.c Wed Feb 3 23:03:24 1999
@@ -9,6 +9,10 @@
#include
#include
+#include
+
+spinlock_t dma_spin_lock = SPIN_LOCK_UNLOCKED;
+
int request_dma(int channel, const char *device_id)
{
return -EINVAL;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/dma-ebsa285.c linux.ac/arch/arm/kernel/dma-ebsa285.c
--- linux.vanilla/arch/arm/kernel/dma-ebsa285.c Tue Dec 22 23:19:26 1998
+++ linux.ac/arch/arm/kernel/dma-ebsa285.c Fri Jan 22 09:07:31 1999
@@ -30,10 +30,11 @@
case 0:
case 1: /* 21285 internal channels */
return 0;
-
+#ifdef CONFIG_ISA_DMA
case 2 ... 9:
- if (machine_is_cats())
+ if (machine_is_cats() || machine_is_netwinder())
return isa_request_dma(channel - 2, dma, dev_name);
+#endif
}
return -EINVAL;
@@ -52,10 +53,9 @@
case 0:
case 1:
break;
-#ifdef CONFIG_CATS
+#ifdef CONFIG_ISA_DMA
case 2 ... 9:
- if (machine_is_cats())
- residue = isa_get_dma_residue(channel - 2);
+ residue = isa_get_dma_residue(channel - 2, dma);
#endif
}
return residue;
@@ -70,10 +70,9 @@
* Not yet implemented
*/
break;
-#ifdef CONFIG_CATS
+#ifdef CONFIG_ISA_DMA
case 2 ... 9:
- if (machine_is_cats())
- isa_enable_dma(channel - 2, dma);
+ isa_enable_dma(channel - 2, dma);
#endif
}
}
@@ -87,15 +86,17 @@
* Not yet implemented
*/
break;
-#ifdef CONFIG_CATS
+#ifdef CONFIG_ISA_DMA
case 2 ... 9:
- if (machine_is_cats())
- isa_disable_dma(channel - 2, dma);
+ isa_disable_dma(channel - 2, dma);
#endif
}
}
__initfunc(void arch_dma_init(dma_t *dma))
{
- /* Nothing to do */
+#ifdef CONFIG_ISA_DMA
+ if (machine_is_cats() || machine_is_netwinder())
+ isa_init_dma();
+#endif
}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/dma-isa.c linux.ac/arch/arm/kernel/dma-isa.c
--- linux.vanilla/arch/arm/kernel/dma-isa.c Tue Dec 22 23:19:26 1998
+++ linux.ac/arch/arm/kernel/dma-isa.c Tue Feb 2 20:29:26 1999
@@ -11,6 +11,7 @@
* Copyright (C) 1998 Phil Blundell
*/
#include
+#include
#include
#include
@@ -18,6 +19,11 @@
#include "dma.h"
#include "dma-isa.h"
+#define ISA_DMA_MODE_READ 0x44
+#define ISA_DMA_MODE_WRITE 0x48
+#define ISA_DMA_MODE_CASCADE 0xc0
+#define ISA_DMA_AUTOINIT 0x10
+
#define ISA_DMA_MASK 0
#define ISA_DMA_MODE 1
#define ISA_DMA_CLRFF 2
@@ -56,25 +62,27 @@
unsigned int io_port = isa_dma_port[channel][ISA_DMA_COUNT];
int count;
- count = 1 + inb(io_port) + (inb(io_port) << 8);
+ count = 1 + inb(io_port);
+ count |= inb(io_port) << 8;
return channel < 4 ? count : (count << 1);
}
void isa_enable_dma(int channel, dma_t *dma)
{
- unsigned long address, length;
-
if (dma->invalid) {
+ unsigned long address, length;
+ unsigned int mode;
+
address = dma->buf.address;
length = dma->buf.length - 1;
- outb(address >> 24, isa_dma_port[channel][ISA_DMA_PGHI]);
outb(address >> 16, isa_dma_port[channel][ISA_DMA_PGLO]);
+ outb(address >> 24, isa_dma_port[channel][ISA_DMA_PGHI]);
if (channel >= 4) {
address >>= 1;
- length = (length >> 1) & 0xfe; /* why &0xfe? */
+ length >>= 1;
}
outb(0, isa_dma_port[channel][ISA_DMA_CLRFF]);
@@ -85,17 +93,31 @@
outb(length, isa_dma_port[channel][ISA_DMA_COUNT]);
outb(length >> 8, isa_dma_port[channel][ISA_DMA_COUNT]);
- outb(dma->dma_mode | (channel & 3), isa_dma_port[channel][ISA_DMA_MODE]);
+ mode = channel & 3;
- switch (dma->dma_mode) {
+ switch (dma->dma_mode & DMA_MODE_MASK) {
case DMA_MODE_READ:
+ mode |= ISA_DMA_MODE_READ;
dma_cache_inv(__bus_to_virt(dma->buf.address), dma->buf.length);
break;
case DMA_MODE_WRITE:
+ mode |= ISA_DMA_MODE_WRITE;
dma_cache_wback(__bus_to_virt(dma->buf.address), dma->buf.length);
break;
+
+ case DMA_MODE_CASCADE:
+ mode |= ISA_DMA_MODE_CASCADE;
+ break;
+
+ default:
+ break;
}
+
+ if (dma->dma_mode & DMA_AUTOINIT)
+ mode |= ISA_DMA_AUTOINIT;
+
+ outb(mode, isa_dma_port[channel][ISA_DMA_MODE]);
dma->invalid = 0;
}
outb(channel & 3, isa_dma_port[channel][ISA_DMA_MASK]);
@@ -104,4 +126,39 @@
void isa_disable_dma(int channel, dma_t *dma)
{
outb(channel | 4, isa_dma_port[channel][ISA_DMA_MASK]);
+}
+
+__initfunc(void isa_init_dma(void))
+{
+ int channel;
+
+ outb(0xff, 0x0d);
+ outb(0xff, 0xda);
+
+ for (channel = 0; channel < 8; channel++)
+ isa_disable_dma(channel, NULL);
+
+ outb(0x40, 0x0b);
+ outb(0x41, 0x0b);
+ outb(0x42, 0x0b);
+ outb(0x43, 0x0b);
+
+ outb(0xc0, 0xd6);
+ outb(0x41, 0xd6);
+ outb(0x42, 0xd6);
+ outb(0x43, 0xd6);
+
+ outb(0, 0xd4);
+
+ outb(0x10, 0x08);
+ outb(0x10, 0xd0);
+
+ outb(0x30, 0x40b);
+ outb(0x31, 0x40b);
+ outb(0x32, 0x40b);
+ outb(0x33, 0x40b);
+
+ outb(0x31, 0x4d6);
+ outb(0x32, 0x4d6);
+ outb(0x33, 0x4d6);
}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/dma-isa.h linux.ac/arch/arm/kernel/dma-isa.h
--- linux.vanilla/arch/arm/kernel/dma-isa.h Tue Dec 22 23:19:26 1998
+++ linux.ac/arch/arm/kernel/dma-isa.h Sun Dec 27 21:51:17 1998
@@ -23,3 +23,7 @@
*/
void isa_disable_dma(int channel, dma_t *dma);
+/*
+ * Initialise DMA
+ */
+void isa_init_dma(void);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/dma-rpc.c linux.ac/arch/arm/kernel/dma-rpc.c
--- linux.vanilla/arch/arm/kernel/dma-rpc.c Sun Nov 8 15:08:43 1998
+++ linux.ac/arch/arm/kernel/dma-rpc.c Tue Feb 2 20:31:32 1999
@@ -15,6 +15,7 @@
#include
#include
#include
+#include
#include
#include
@@ -223,8 +224,9 @@
break;
case DMA_VIRTUAL_FLOPPY: {
- extern int floppy_fiqresidual(void);
- residue = floppy_fiqresidual();
+ struct pt_regs regs;
+ get_fiq_regs(®s);
+ return regs.ARM_r9;
}
break;
}
@@ -286,7 +288,6 @@
set_fiq_handler(fiqhandler_start, fiqhandler_length);
set_fiq_regs(®s);
enable_irq(dma->dma_irq);
-
}
break;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/dma-vnc.c linux.ac/arch/arm/kernel/dma-vnc.c
--- linux.vanilla/arch/arm/kernel/dma-vnc.c Tue Dec 22 23:19:26 1998
+++ linux.ac/arch/arm/kernel/dma-vnc.c Thu Jan 1 01:00:00 1970
@@ -1,51 +0,0 @@
-/*
- * arch/arm/kernel/dma-vnc.c
- *
- * Copyright (C) 1998 Russell King
- */
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-
-#include "dma.h"
-#include "dma-isa.h"
-
-int arch_request_dma(dmach_t channel, dma_t *dma, const char *dev_name)
-{
- if (channel < 8)
- return isa_request_dma(channel, dma, dev_name);
- return -EINVAL;
-}
-
-void arch_free_dma(dmach_t channel, dma_t *dma)
-{
- isa_free_dma(channel, dma);
-}
-
-int arch_get_dma_residue(dmach_t channel, dma_t *dma)
-{
- return isa_get_dma_residue(channel, dma);
-}
-
-void arch_enable_dma(dmach_t channel, dma_t *dma)
-{
- isa_enable_dma(channel, dma);
-}
-
-void arch_disable_dma(dmach_t channel, dma_t *dma)
-{
- isa_disable_dma(channel, dma);
-}
-
-__initfunc(void arch_dma_init(dma_t *dma))
-{
- /* Nothing to do */
-}
-
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/ecard.c linux.ac/arch/arm/kernel/ecard.c
--- linux.vanilla/arch/arm/kernel/ecard.c Mon Dec 28 23:09:40 1998
+++ linux.ac/arch/arm/kernel/ecard.c Sun Feb 28 09:55:43 1999
@@ -7,32 +7,41 @@
*
* Created from information from Acorns RiscOS3 PRMs
*
- * 08-Dec-1996 RMK Added code for the 9'th expansion card - the ether podule slot.
+ * 08-Dec-1996 RMK Added code for the 9'th expansion card - the ether
+ * podule slot.
* 06-May-1997 RMK Added blacklist for cards whose loader doesn't work.
- * 12-Sep-1997 RMK Created new handling of interrupt enables/disables - cards can
- * now register their own routine to control interrupts (recommended).
- * 29-Sep-1997 RMK Expansion card interrupt hardware not being re-enabled on reset from
- * Linux. (Caused cards not to respond under RiscOS without hard reset).
+ * 12-Sep-1997 RMK Created new handling of interrupt enables/disables
+ * - cards can now register their own routine to control
+ * interrupts (recommended).
+ * 29-Sep-1997 RMK Expansion card interrupt hardware not being re-enabled
+ * on reset from Linux. (Caused cards not to respond
+ * under RiscOS without hard reset).
* 15-Feb-1998 RMK Added DMA support
* 12-Sep-1998 RMK Added EASI support
+ * 10-Jan-1999 RMK Run loaders in a simulated RISC OS environment.
*/
#define ECARD_C
+#define __KERNEL_SYSCALLS__
#include
+#include
#include
#include
#include
#include
#include
#include
+#include
+#include
#include
-#include
-#include
+#include
#include
+#include
+#include
#include
-#include
+#include
#ifdef CONFIG_ARCH_ARC
#include
@@ -40,45 +49,419 @@
#define oldlatch_init()
#endif
-#define BLACKLIST_NAME(m,p,s) { m, p, NULL, s }
-#define BLACKLIST_LOADER(m,p,l) { m, p, l, NULL }
-#define BLACKLIST_NOLOADER(m,p) { m, p, noloader, blacklisted_str }
-#define BUS_ADDR(x) ((((unsigned long)(x)) << 2) + IO_BASE)
+enum req {
+ req_readbytes,
+ req_reset
+};
-extern unsigned long atomwide_serial_loader[], oak_scsi_loader[], noloader[];
-static const char blacklisted_str[] = "*loader s/w is not 32-bit compliant*";
+struct ecard_request {
+ enum req req;
+ ecard_t *ec;
+ unsigned int address;
+ unsigned int length;
+ unsigned int use_loader;
+ void *buffer;
+};
-static const struct expcard_blacklist {
+struct expcard_blacklist {
unsigned short manufacturer;
unsigned short product;
- const loader_t loader;
const char *type;
-} blacklist[] = {
-/* Cards without names */
- BLACKLIST_NAME(MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1"),
-
-/* Cards with corrected loader */
- BLACKLIST_LOADER(MANU_ATOMWIDE, PROD_ATOMWIDE_3PSERIAL, atomwide_serial_loader),
- BLACKLIST_LOADER(MANU_OAK, PROD_OAK_SCSI, oak_scsi_loader),
+};
-/* Supported cards with broken loader */
- { MANU_ALSYSTEMS, PROD_ALSYS_SCSIATAPI, noloader, "AlSystems PowerTec SCSI" },
+static ecard_t *cards;
+static ecard_t *slot_to_expcard[MAX_ECARDS];
+#ifdef HAS_EXPMASK
+static unsigned int have_expmask;
+#endif
-/* Unsupported cards with no loader */
- BLACKLIST_NOLOADER(MANU_MCS, PROD_MCS_CONNECT32)
+/* List of descriptions of cards which don't have an extended
+ * identification, or chunk directories containing a description.
+ */
+static const struct expcard_blacklist __init blacklist[] = {
+ { MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1" }
};
+asmlinkage extern int
+ecard_loader_reset(volatile unsigned char *pa, loader_t loader);
+asmlinkage extern int
+ecard_loader_read(int off, volatile unsigned char *pa, loader_t loader);
extern int setup_arm_irq(int, struct irqaction *);
+extern void do_ecard_IRQ(int, struct pt_regs *);
+
+
+static void
+ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs);
+
+static struct irqaction irqexpansioncard = {
+ ecard_irq_noexpmask, SA_INTERRUPT, 0, "expansion cards", NULL, NULL
+};
+
+static inline unsigned short
+ecard_getu16(unsigned char *v)
+{
+ return v[0] | v[1] << 8;
+}
+
+static inline signed long
+ecard_gets24(unsigned char *v)
+{
+ return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0);
+}
+static inline ecard_t *
+slot_to_ecard(unsigned int slot)
+{
+ return slot < MAX_ECARDS ? slot_to_expcard[slot] : NULL;
+}
+
+/* ===================== Expansion card daemon ======================== */
/*
- * from linux/arch/arm/kernel/irq.c
+ * Since the loader programs on the expansion cards need to be run
+ * in a specific environment, create a separate task with this
+ * environment up, and pass requests to this task as and when we
+ * need to.
+ *
+ * This should allow 99% of loaders to be called from Linux.
+ *
+ * From a security standpoint, we trust the card vendors. This
+ * may be a misplaced trust.
*/
-extern void do_ecard_IRQ(int irq, struct pt_regs *);
+#define BUS_ADDR(x) ((((unsigned long)(x)) << 2) + IO_BASE)
+#define POD_INT_ADDR(x) ((volatile unsigned char *)\
+ ((BUS_ADDR((x)) - IO_BASE) + IO_START))
-static ecard_t expcard[MAX_ECARDS];
-static signed char irqno_to_expcard[16];
-static unsigned int ecard_numcards, ecard_numirqcards;
-static unsigned int have_expmask;
+static void
+ecard_task_reset(struct ecard_request *req)
+{
+ if (req->ec == NULL) {
+ ecard_t *ec;
+
+ for (ec = cards; ec; ec = ec->next) {
+ printk(KERN_DEBUG "Resetting card %d\n",
+ ec->slot_no);
+
+ if (ec->loader)
+ ecard_loader_reset(POD_INT_ADDR(ec->podaddr),
+ ec->loader);
+ }
+ printk(KERN_DEBUG "All cards reset\n");
+ } else if (req->ec->loader)
+ ecard_loader_reset(POD_INT_ADDR(req->ec->podaddr),
+ req->ec->loader);
+}
+
+static void
+ecard_task_readbytes(struct ecard_request *req)
+{
+ unsigned char *buf = (unsigned char *)req->buffer;
+ volatile unsigned char *base_addr =
+ (volatile unsigned char *)POD_INT_ADDR(req->ec->podaddr);
+ unsigned int len = req->length;
+
+ if (req->ec->slot_no == 8) {
+ /*
+ * The card maintains an index which
+ * increments the address into a 4096-byte
+ * page on each access. We need to keep
+ * track of the counter.
+ */
+ static unsigned int index;
+ unsigned int offset, page;
+ unsigned char byte = 0; /* keep gcc quiet */
+
+ offset = req->address & 4095;
+ page = req->address >> 12;
+
+ if (page > 256)
+ return;
+
+ page *= 4;
+
+ if (offset == 0 || index > offset) {
+ /*
+ * We need to reset the index counter.
+ */
+ *base_addr = 0;
+ index = 0;
+ }
+
+ while (index <= offset) {
+ byte = base_addr[page];
+ index += 1;
+ }
+
+ while (len--) {
+ *buf++ = byte;
+ if (len) {
+ byte = base_addr[page];
+ index += 1;
+ }
+ }
+ } else {
+ unsigned int off = req->address;
+
+ if (!req->use_loader || !req->ec->loader) {
+ off *= 4;
+ while (len--) {
+ *buf++ = base_addr[off];
+ off += 4;
+ }
+ } else {
+ while(len--) {
+ /*
+ * The following is required by some
+ * expansion card loader programs.
+ */
+ *(unsigned long *)0x108 = 0;
+ *buf++ = ecard_loader_read(off++, base_addr,
+ req->ec->loader);
+ }
+ }
+ }
+
+}
+
+#ifdef CONFIG_CPU_32
+static pid_t ecard_pid;
+static struct wait_queue *ecard_wait;
+static struct wait_queue *ecard_done;
+static struct ecard_request *ecard_req;
+
+/*
+ * Set up the expansion card daemon's environment.
+ */
+static void
+ecard_init_task(void)
+{
+ /* We want to set up the page tables for the following mapping:
+ * Virtual Physical
+ * 0x03000000 0x03000000
+ * 0x03010000 unmapped
+ * 0x03210000 0x03210000
+ * 0x03400000 unmapped
+ * 0x08000000 0x08000000
+ * 0x10000000 unmapped
+ *
+ * FIXME: we don't follow this 100% yet.
+ */
+ pgd_t *src_pgd, *dst_pgd;
+ unsigned int dst_addr = IO_START;
+
+ src_pgd = pgd_offset(current->mm, IO_BASE);
+ dst_pgd = pgd_offset(current->mm, dst_addr);
+
+ while (dst_addr < IO_START + IO_SIZE) {
+ *dst_pgd++ = *src_pgd++;
+ dst_addr += PGDIR_SIZE;
+ }
+
+ flush_tlb_range(current->mm, IO_START, IO_START + IO_SIZE);
+
+ dst_addr = EASI_START;
+ src_pgd = pgd_offset(current->mm, EASI_BASE);
+ dst_pgd = pgd_offset(current->mm, dst_addr);
+
+ while (dst_addr < EASI_START + EASI_SIZE) {
+ *dst_pgd++ = *src_pgd++;
+ dst_addr += PGDIR_SIZE;
+ }
+
+ flush_tlb_range(current->mm, EASI_START, EASI_START + EASI_SIZE);
+}
+
+static int
+ecard_task(void * unused)
+{
+ current->session = 1;
+ current->pgrp = 1;
+
+ /*
+ * We don't want /any/ signals, not even SIGKILL
+ */
+ sigfillset(¤t->blocked);
+ sigemptyset(¤t->signal);
+
+ strcpy(current->comm, "kecardd");
+
+ /*
+ * Set up the environment
+ */
+ ecard_init_task();
+
+ while (1) {
+ struct ecard_request *req;
+
+ do {
+ req = xchg(&ecard_req, NULL);
+
+ if (req == NULL) {
+ sigemptyset(¤t->signal);
+ interruptible_sleep_on(&ecard_wait);
+ }
+ } while (req == NULL);
+
+ switch (req->req) {
+ case req_readbytes:
+ ecard_task_readbytes(req);
+ break;
+
+ case req_reset:
+ ecard_task_reset(req);
+ break;
+ }
+ wake_up(&ecard_done);
+ }
+}
+
+/*
+ * Wake the expansion card daemon to action our request.
+ *
+ * FIXME: The test here is not sufficient to detect if the
+ * kcardd is running.
+ */
+static inline void
+ecard_call(struct ecard_request *req)
+{
+ /*
+ * If we're called from task 0, or from an
+ * interrupt (will be keyboard interrupt),
+ * we forcefully set up the memory map, and
+ * call the loader. We can't schedule, or
+ * sleep for this call.
+ */
+ if ((current == task[0] || in_interrupt()) &&
+ req->req == req_reset && req->ec == NULL) {
+ ecard_init_task();
+ ecard_task_reset(req);
+ } else {
+ if (ecard_pid <= 0)
+ ecard_pid = kernel_thread(ecard_task, NULL, 0);
+
+ ecard_req = req;
+
+ wake_up(&ecard_wait);
+
+ sleep_on(&ecard_done);
+ }
+}
+#else
+/*
+ * On 26-bit processors, we don't need the kcardd thread to access the
+ * expansion card loaders. We do it directly.
+ */
+static inline void
+ecard_call(struct ecard_request *req)
+{
+ if (req->req == req_reset)
+ ecard_task_reset(req);
+ else
+ ecard_task_readbytes(req);
+}
+#endif
+
+/* ======================= Mid-level card control ===================== */
+/*
+ * This is called to reset the loaders for each expansion card on reboot.
+ *
+ * This is required to make sure that the card is in the correct state
+ * that RiscOS expects it to be.
+ */
+void
+ecard_reset(int slot)
+{
+ struct ecard_request req;
+
+ req.req = req_reset;
+
+ if (slot < 0)
+ req.ec = NULL;
+ else
+ req.ec = slot_to_ecard(slot);
+
+ ecard_call(&req);
+
+#ifdef HAS_EXPMASK
+ if (have_expmask && slot < 0) {
+ have_expmask |= ~0;
+ EXPMASK_ENABLE = have_expmask;
+ }
+#endif
+}
+
+static void
+ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld)
+{
+ struct ecard_request req;
+
+ req.req = req_readbytes;
+ req.ec = ec;
+ req.address = off;
+ req.length = len;
+ req.use_loader = useld;
+ req.buffer = addr;
+
+ ecard_call(&req);
+}
+
+int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num)
+{
+ struct ex_chunk_dir excd;
+ int index = 16;
+ int useld = 0;
+
+ if (!ec->cid.cd)
+ return 0;
+
+ while(1) {
+ ecard_readbytes(&excd, ec, index, 8, useld);
+ index += 8;
+ if (c_id(&excd) == 0) {
+ if (!useld && ec->loader) {
+ useld = 1;
+ index = 0;
+ continue;
+ }
+ return 0;
+ }
+ if (c_id(&excd) == 0xf0) { /* link */
+ index = c_start(&excd);
+ continue;
+ }
+ if (c_id(&excd) == 0x80) { /* loader */
+ if (!ec->loader) {
+ ec->loader = (loader_t)kmalloc(c_len(&excd),
+ GFP_KERNEL);
+ if (ec->loader)
+ ecard_readbytes(ec->loader, ec,
+ (int)c_start(&excd),
+ c_len(&excd), useld);
+ else
+ return 0;
+ }
+ continue;
+ }
+ if (c_id(&excd) == id && num-- == 0)
+ break;
+ }
+
+ if (c_id(&excd) & 0x80) {
+ switch (c_id(&excd) & 0x70) {
+ case 0x70:
+ ecard_readbytes((unsigned char *)excd.d.string, ec,
+ (int)c_start(&excd), c_len(&excd),
+ useld);
+ break;
+ case 0x00:
+ break;
+ }
+ }
+ cd->start_offset = c_start(&excd);
+ memcpy(cd->d.string, excd.d.string, 256);
+ return 1;
+}
+
+/* ======================= Interrupt control ============================ */
static void ecard_def_irq_enable(ecard_t *ec, int irqnr)
{
@@ -100,6 +483,11 @@
#endif
}
+static int ecard_def_irq_pending(ecard_t *ec)
+{
+ return !ec->irqmask || ec->irqaddr[0] & ec->irqmask;
+}
+
static void ecard_def_fiq_enable(ecard_t *ec, int fiqnr)
{
panic("ecard_def_fiq_enable called - impossible");
@@ -110,11 +498,18 @@
panic("ecard_def_fiq_disable called - impossible");
}
+static int ecard_def_fiq_pending(ecard_t *ec)
+{
+ return !ec->fiqmask || ec->fiqaddr[0] & ec->fiqmask;
+}
+
static expansioncard_ops_t ecard_default_ops = {
ecard_def_irq_enable,
ecard_def_irq_disable,
+ ecard_def_irq_pending,
ecard_def_fiq_enable,
- ecard_def_fiq_disable
+ ecard_def_fiq_disable,
+ ecard_def_fiq_pending
};
/*
@@ -125,10 +520,9 @@
*/
void ecard_enableirq(unsigned int irqnr)
{
- irqnr &= 7;
- if (irqnr < MAX_ECARDS && irqno_to_expcard[irqnr] != -1) {
- ecard_t *ec = expcard + irqno_to_expcard[irqnr];
+ ecard_t *ec = slot_to_ecard(irqnr);
+ if (ec) {
if (!ec->ops)
ec->ops = &ecard_default_ops;
@@ -142,10 +536,9 @@
void ecard_disableirq(unsigned int irqnr)
{
- irqnr &= 7;
- if (irqnr < MAX_ECARDS && irqno_to_expcard[irqnr] != -1) {
- ecard_t *ec = expcard + irqno_to_expcard[irqnr];
+ ecard_t *ec = slot_to_ecard(irqnr);
+ if (ec) {
if (!ec->ops)
ec->ops = &ecard_default_ops;
@@ -156,10 +549,9 @@
void ecard_enablefiq(unsigned int fiqnr)
{
- fiqnr &= 7;
- if (fiqnr < MAX_ECARDS && irqno_to_expcard[fiqnr] != -1) {
- ecard_t *ec = expcard + irqno_to_expcard[fiqnr];
+ ecard_t *ec = slot_to_ecard(fiqnr);
+ if (ec) {
if (!ec->ops)
ec->ops = &ecard_default_ops;
@@ -173,10 +565,9 @@
void ecard_disablefiq(unsigned int fiqnr)
{
- fiqnr &= 7;
- if (fiqnr < MAX_ECARDS && irqno_to_expcard[fiqnr] != -1) {
- ecard_t *ec = expcard + irqno_to_expcard[fiqnr];
+ ecard_t *ec = slot_to_ecard(fiqnr);
+ if (ec) {
if (!ec->ops)
ec->ops = &ecard_default_ops;
@@ -185,41 +576,89 @@
}
}
-static void ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs)
+static void
+ecard_dump_irq_state(ecard_t *ec)
{
- const int num_cards = ecard_numirqcards;
- int i, called = 0;
+ printk(" %d: %sclaimed, ",
+ ec->slot_no,
+ ec->claimed ? "" : "not ");
+
+ if (ec->ops && ec->ops->irqpending &&
+ ec->ops != &ecard_default_ops)
+ printk("irq %spending\n",
+ ec->ops->irqpending(ec) ? "" : "not ");
+ else
+ printk("irqaddr %p, mask = %02X, status = %02X\n",
+ ec->irqaddr, ec->irqmask, *ec->irqaddr);
+}
- for (i = 0; i < num_cards; i++) {
- if (expcard[i].claimed && expcard[i].irq &&
- (!expcard[i].irqmask ||
- expcard[i].irqaddr[0] & expcard[i].irqmask)) {
- do_ecard_IRQ(expcard[i].irq, regs);
- called ++;
+static void
+ecard_check_lockup(void)
+{
+ static int last, lockup;
+ ecard_t *ec;
+
+ /*
+ * If the timer interrupt has not run since the last million
+ * unrecognised expansion card interrupts, then there is
+ * something seriously wrong. Disable the expansion card
+ * interrupts so at least we can continue.
+ *
+ * Maybe we ought to start a timer to re-enable them some time
+ * later?
+ */
+ if (last == jiffies) {
+ lockup += 1;
+ if (lockup > 1000000) {
+ printk(KERN_ERR "\nInterrupt lockup detected - "
+ "disabling all expansion card interrupts\n");
+
+ disable_irq(IRQ_EXPANSIONCARD);
+
+ printk("Expansion card IRQ state:\n");
+
+ for (ec = cards; ec; ec = ec->next)
+ ecard_dump_irq_state(ec);
}
+ } else
+ lockup = 0;
+
+ /*
+ * If we did not recognise the source of this interrupt,
+ * warn the user, but don't flood the user with these messages.
+ */
+ if (!last || time_after(jiffies, last + 5*HZ)) {
+ last = jiffies;
+ printk(KERN_WARNING "Unrecognised interrupt from backplane\n");
}
- cli();
- if (called == 0) {
- static int last, lockup;
+}
- if (last == jiffies) {
- lockup += 1;
- if (lockup > 1000000) {
- printk(KERN_ERR "\nInterrupt lockup detected - disabling expansion card IRQs\n");
- disable_irq(intr_no);
- printk("Expansion card IRQ state:\n");
- for (i = 0; i < num_cards; i++)
- printk(" %d: %sclaimed, irqaddr = %p, irqmask = %X, status=%X\n", expcard[i].irq - 32,
- expcard[i].claimed ? "" : "not", expcard[i].irqaddr, expcard[i].irqmask, *expcard[i].irqaddr);
- }
- } else
- lockup = 0;
+static void
+ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs)
+{
+ ecard_t *ec;
+ int called = 0;
+
+ for (ec = cards; ec; ec = ec->next) {
+ int pending;
+
+ if (!ec->claimed || ec->irq == NO_IRQ || ec->slot_no == 8)
+ continue;
+
+ if (ec->ops && ec->ops->irqpending)
+ pending = ec->ops->irqpending(ec);
+ else
+ pending = ecard_default_ops.irqpending(ec);
- if (!last || time_after(jiffies, last + 5*HZ)) {
- last = jiffies;
- printk(KERN_ERR "\nUnrecognised interrupt from backplane\n");
+ if (pending) {
+ do_ecard_IRQ(ec->irq, regs);
+ called ++;
}
}
+ cli();
+
+ if (called == 0)
+ ecard_check_lockup();
}
#ifdef HAS_EXPMASK
@@ -234,31 +673,35 @@
0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00
};
-static void ecard_irq_expmask(int intr_no, void *dev_id, struct pt_regs *regs)
+static void
+ecard_irq_expmask(int intr_no, void *dev_id, struct pt_regs *regs)
{
const unsigned int statusmask = 15;
unsigned int status;
status = EXPMASK_STATUS & statusmask;
if (status) {
- unsigned int irqno;
+ unsigned int slot;
ecard_t *ec;
again:
- irqno = first_set[status];
- ec = expcard + irqno_to_expcard[irqno];
+ slot = first_set[status];
+ ec = slot_to_ecard(slot);
if (ec->claimed) {
unsigned int oldexpmask;
/*
- * this ugly code is so that we can operate a prioritorising system.
+ * this ugly code is so that we can operate a
+ * prioritorising system:
+ *
* Card 0 highest priority
* Card 1
* Card 2
* Card 3 lowest priority
+ *
* Serial cards should go in 0/1, ethernet/scsi in 2/3
* otherwise you will lose serial data at high speeds!
*/
oldexpmask = have_expmask;
- EXPMASK_ENABLE = (have_expmask &= priority_masks[irqno]);
+ EXPMASK_ENABLE = (have_expmask &= priority_masks[slot]);
sti();
do_ecard_IRQ(ec->irq, regs);
cli();
@@ -267,15 +710,18 @@
if (status)
goto again;
} else {
- printk(KERN_WARNING "card%d: interrupt from unclaimed card???\n", irqno);
- EXPMASK_ENABLE = (have_expmask &= ~(1 << irqno));
+ printk(KERN_WARNING "card%d: interrupt from unclaimed "
+ "card???\n", slot);
+ EXPMASK_ENABLE = (have_expmask &= ~(1 << slot));
}
} else
printk(KERN_WARNING "Wild interrupt from backplane (masks)\n");
}
-static int ecard_checkirqhw(void)
+__initfunc(static void
+ecard_probeirqhw(void))
{
+ ecard_t *ec;
int found;
EXPMASK_ENABLE = 0x00;
@@ -283,62 +729,77 @@
found = ((EXPMASK_STATUS & 15) == 0);
EXPMASK_ENABLE = 0xff;
- return found;
+ if (!found)
+ return;
+
+ printk(KERN_DEBUG "Expansion card interrupt "
+ "management hardware found\n");
+
+ irqexpansioncard.handler = ecard_irq_expmask;
+
+ /* for each card present, set a bit to '1' */
+ have_expmask = 0x80000000;
+
+ for (ec = cards; ec; ec = ec->next)
+ have_expmask |= 1 << ec->slot_no;
+
+ EXPMASK_ENABLE = have_expmask;
}
+#else
+#define ecard_probeirqhw()
#endif
-static void ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld)
+unsigned int ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed)
{
- extern int ecard_loader_read(int off, volatile unsigned int pa, loader_t loader);
- unsigned char *a = (unsigned char *)addr;
-
- if (ec->slot_no == 8) {
- static unsigned int lowaddress;
- unsigned int laddr, haddr;
- unsigned char byte = 0; /* keep gcc quiet */
-
- laddr = off & 4095; /* number of bytes to read from offset + base addr */
- haddr = off >> 12; /* offset into card from base addr */
+ switch (ec->slot_no) {
+ case 0 ... 3:
+ switch (type) {
+ case ECARD_MEMC:
+ return IO_EC_MEMC_BASE + (ec->slot_no << 12);
- if (haddr > 256)
- return;
+ case ECARD_IOC:
+ return IO_EC_IOC_BASE + (speed << 17) +
+ (ec->slot_no << 12);
- /*
- * If we require a low address or address 0, then reset, and start again...
- */
- if (!off || lowaddress > laddr) {
- outb(0, ec->podaddr);
- lowaddress = 0;
- }
- while (lowaddress <= laddr) {
- byte = inb(ec->podaddr + haddr);
- lowaddress += 1;
- }
- while (len--) {
- *a++ = byte;
- if (len) {
- byte = inb(ec->podaddr + haddr);
- lowaddress += 1;
- }
+#ifdef IO_EC_EASI_BASE
+ case ECARD_EASI:
+ return IO_EC_EASI_BASE + (ec->slot_no << 22);
+#endif
+ default:
+ break;
}
- } else {
- if (!useld || !ec->loader) {
- while(len--)
- *a++ = inb(ec->podaddr + (off++));
- } else {
- while(len--) {
- *(unsigned long *)0x108 = 0; /* hack for some loaders!!! */
- *a++ = ecard_loader_read(off++, BUS_ADDR(ec->podaddr), ec->loader);
- }
+ break;
+
+ case 4 ... 7:
+ switch (type) {
+#ifdef IO_EC_IOC4_BASE
+ case ECARD_IOC:
+ return IO_EC_IOC4_BASE + (speed << 17) +
+ ((ec->slot_no - 4) << 12);
+#endif
+#ifdef IO_EC_EASI_BASE
+ case ECARD_EASI:
+ return IO_EC_EASI_BASE + (ec->slot_no << 22);
+#endif
+ default:
+ break;
}
+ break;
+
+#ifdef IO_EC_MEMC8_BASE
+ case 8:
+ return IO_EC_MEMC8_BASE;
+#endif
}
+ return 0;
}
static int ecard_prints(char *buffer, ecard_t *ec)
{
char *start = buffer;
- buffer += sprintf(buffer, "\n %d: ", ec->slot_no);
+ buffer += sprintf(buffer, " %d: %s ", ec->slot_no,
+ ec->type == ECARD_EASI ? "EASI" : " ");
if (ec->cid.id == 0) {
struct in_chunk_dir incd;
@@ -346,63 +807,59 @@
buffer += sprintf(buffer, "[%04X:%04X] ",
ec->cid.manufacturer, ec->cid.product);
- if (!ec->card_desc && ec->cid.is && ec->cid.cd &&
+ if (!ec->card_desc && ec->cid.cd &&
ecard_readchunk(&incd, ec, 0xf5, 0))
ec->card_desc = incd.d.string;
if (!ec->card_desc)
ec->card_desc = "*unknown*";
- buffer += sprintf(buffer, "%s", ec->card_desc);
+ buffer += sprintf(buffer, "%s\n", ec->card_desc);
} else
- buffer += sprintf(buffer, "Simple card %d", ec->cid.id);
+ buffer += sprintf(buffer, "Simple card %d\n", ec->cid.id);
return buffer - start;
}
-static inline unsigned short ecard_getu16(unsigned char *v)
-{
- return v[0] | v[1] << 8;
-}
-
-static inline signed long ecard_gets24(unsigned char *v)
-{
- return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0);
-}
-
/*
* Probe for an expansion card.
*
* If bit 1 of the first byte of the card is set, then the
* card does not exist.
*/
-__initfunc(static int ecard_probe(int card, int freeslot, card_type_t type))
+__initfunc(static int
+ecard_probe(int slot, card_type_t type))
{
- ecard_t *ec = expcard + freeslot;
+ ecard_t **ecp;
+ ecard_t *ec;
struct ex_ecid cid;
char buffer[200];
- int i;
+ int i, rc = -ENOMEM;
+
+ ec = kmalloc(sizeof(ecard_t), GFP_KERNEL);
- irqno_to_expcard[card] = -1;
+ if (!ec)
+ goto nodev;
- ec->slot_no = card;
+ memset(ec, 0, sizeof(ecard_t));
+
+ ec->slot_no = slot;
+ ec->type = type;
ec->irq = NO_IRQ;
ec->fiq = NO_IRQ;
ec->dma = NO_DMA;
ec->card_desc = NULL;
ec->ops = &ecard_default_ops;
+ rc = -ENODEV;
if ((ec->podaddr = ecard_address(ec, type, ECARD_SYNC)) == 0)
- return 0;
+ goto nodev;
cid.r_zero = 1;
ecard_readbytes(&cid, ec, 0, 16, 0);
if (cid.r_zero)
- return 0;
-
- irqno_to_expcard[card] = freeslot;
+ goto nodev;
- ec->type = type;
ec->cid.id = cid.r_id;
ec->cid.cd = cid.r_cd;
ec->cid.is = cid.r_is;
@@ -415,9 +872,9 @@
ec->cid.fiqmask = cid.r_fiqmask;
ec->cid.fiqoff = ecard_gets24(cid.r_fiqoff);
ec->fiqaddr =
- ec->irqaddr = (unsigned char *)BUS_ADDR(ec->podaddr);
+ ec->irqaddr = (unsigned char *)ioaddr(ec->podaddr);
- if (ec->cid.cd && ec->cid.is) {
+ if (ec->cid.is) {
ec->irqmask = ec->cid.irqmask;
ec->irqaddr += ec->cid.irqoff;
ec->fiqmask = ec->cid.fiqmask;
@@ -430,88 +887,69 @@
for (i = 0; i < sizeof(blacklist) / sizeof(*blacklist); i++)
if (blacklist[i].manufacturer == ec->cid.manufacturer &&
blacklist[i].product == ec->cid.product) {
- ec->loader = blacklist[i].loader;
ec->card_desc = blacklist[i].type;
break;
}
- ecard_prints(buffer, ec);
- printk("%s", buffer);
-
- ec->irq = 32 + card;
+ ec->irq = 32 + slot;
#ifdef IO_EC_MEMC8_BASE
- if (card == 8)
+ if (slot == 8)
ec->irq = 11;
#endif
#ifdef CONFIG_ARCH_RPC
/* On RiscPC, only first two slots have DMA capability */
- if (card < 2)
- ec->dma = 2 + card;
+ if (slot < 2)
+ ec->dma = 2 + slot;
#endif
#if 0 /* We don't support FIQs on expansion cards at the moment */
- ec->fiq = 96 + card;
+ ec->fiq = 96 + slot;
#endif
- return 1;
-}
+ rc = 0;
-/*
- * This is called to reset the loaders for each expansion card on reboot.
- *
- * This is required to make sure that the card is in the correct state
- * that RiscOS expects it to be.
- */
-void ecard_reset(int card)
-{
- extern int ecard_loader_reset(volatile unsigned int pa, loader_t loader);
+ for (ecp = &cards; *ecp; ecp = &(*ecp)->next);
- if (card >= ecard_numcards)
- return;
-
- if (card < 0) {
- for (card = 0; card < ecard_numcards; card++)
- if (expcard[card].loader)
- ecard_loader_reset(BUS_ADDR(expcard[card].podaddr),
- expcard[card].loader);
- } else
- if (expcard[card].loader)
- ecard_loader_reset(BUS_ADDR(expcard[card].podaddr),
- expcard[card].loader);
+ *ecp = ec;
-#ifdef HAS_EXPMASK
- if (have_expmask) {
- have_expmask |= ~0;
- EXPMASK_ENABLE = have_expmask;
+nodev:
+ if (rc && ec)
+ kfree(ec);
+ else {
+ slot_to_expcard[slot] = ec;
+
+ ecard_prints(buffer, ec);
+ printk("%s", buffer);
}
-#endif
+ return rc;
}
-static unsigned int ecard_startcard;
+static ecard_t *finding_pos;
void ecard_startfind(void)
{
- ecard_startcard = 0;
+ finding_pos = NULL;
}
ecard_t *ecard_find(int cid, const card_ids *cids)
{
- int card;
+ if (!finding_pos)
+ finding_pos = cards;
+ else
+ finding_pos = finding_pos->next;
- if (!cids) {
- for (card = ecard_startcard; card < ecard_numcards; card++)
- if (!expcard[card].claimed &&
- (expcard[card].cid.id ^ cid) == 0)
+ for (; finding_pos; finding_pos = finding_pos->next) {
+ if (finding_pos->claimed)
+ continue;
+
+ if (!cids) {
+ if ((finding_pos->cid.id ^ cid) == 0)
break;
- } else {
- for (card = ecard_startcard; card < ecard_numcards; card++) {
+ } else {
unsigned int manufacturer, product;
int i;
- if (expcard[card].claimed)
- continue;
-
- manufacturer = expcard[card].cid.manufacturer;
- product = expcard[card].cid.product;
+ manufacturer = finding_pos->cid.manufacturer;
+ product = finding_pos->cid.product;
for (i = 0; cids[i].manufacturer != 65535; i++)
if (manufacturer == cids[i].manufacturer &&
@@ -523,111 +961,24 @@
}
}
- ecard_startcard = card + 1;
-
- return card < ecard_numcards ? &expcard[card] : NULL;
+ return finding_pos;
}
-int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num)
+__initfunc(static void ecard_free_all(void))
{
- struct ex_chunk_dir excd;
- int index = 16;
- int useld = 0;
+ ecard_t *ec, *ecn;
- if (!ec->cid.is || !ec->cid.cd)
- return 0;
-
- while(1) {
- ecard_readbytes(&excd, ec, index, 8, useld);
- index += 8;
- if (c_id(&excd) == 0) {
- if (!useld && ec->loader) {
- useld = 1;
- index = 0;
- continue;
- }
- return 0;
- }
- if (c_id(&excd) == 0xf0) { /* link */
- index = c_start(&excd);
- continue;
- }
- if (c_id(&excd) == 0x80) { /* loader */
- if (!ec->loader) {
- ec->loader = (loader_t)kmalloc(c_len(&excd), GFP_KERNEL);
- ecard_readbytes(ec->loader, ec, (int)c_start(&excd), c_len(&excd), useld);
- }
- continue;
- }
- if (c_id(&excd) == id && num-- == 0)
- break;
- }
+ for (ec = cards; ec; ec = ecn) {
+ ecn = ec->next;
- if (c_id(&excd) & 0x80) {
- switch (c_id(&excd) & 0x70) {
- case 0x70:
- ecard_readbytes((unsigned char *)excd.d.string, ec,
- (int)c_start(&excd), c_len(&excd), useld);
- break;
- case 0x00:
- break;
- }
+ kfree(ec);
}
- cd->start_offset = c_start(&excd);
- memcpy(cd->d.string, excd.d.string, 256);
- return 1;
-}
-
-unsigned int ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed)
-{
- switch (ec->slot_no) {
- case 0 ... 3:
- switch (type) {
- case ECARD_MEMC:
- return IO_EC_MEMC_BASE + (ec->slot_no << 12);
- case ECARD_IOC:
- return IO_EC_IOC_BASE + (speed << 17) + (ec->slot_no << 12);
-
-#ifdef IO_EC_EASI_BASE
- case ECARD_EASI:
- return IO_EC_EASI_BASE + (ec->slot_no << 22);
-#endif
- }
- break;
-
- case 4 ... 7:
- switch (type) {
-#ifdef IO_EC_IOC4_BASE
- case ECARD_IOC:
- return IO_EC_IOC4_BASE + (speed << 17) + ((ec->slot_no - 4) << 12);
-#endif
-#ifdef IO_EC_EASI_BASE
- case ECARD_EASI:
- return IO_EC_EASI_BASE + (ec->slot_no << 22);
-#endif
- default:
- break;
- }
- break;
+ cards = NULL;
-#ifdef IO_EC_MEMC8_BASE
- case 8:
- return IO_EC_MEMC8_BASE;
-#endif
- }
- return 0;
+ memset(slot_to_expcard, 0, sizeof(slot_to_expcard));
}
-static struct irqaction irqexpansioncard = {
- ecard_irq_noexpmask,
- SA_INTERRUPT,
- 0,
- "expansion cards",
- NULL,
- NULL
-};
-
/*
* Initialise the expansion card system.
* Locate all hardware - interrupt management and
@@ -635,51 +986,31 @@
*/
__initfunc(void ecard_init(void))
{
- int i, nc = 0;
-
- memset(expcard, 0, sizeof(expcard));
-
-#ifdef HAS_EXPMASK
- if (ecard_checkirqhw()) {
- printk(KERN_DEBUG "Expansion card interrupt management hardware found\n");
- irqexpansioncard.handler = ecard_irq_expmask;
- irqexpansioncard.flags |= SA_IRQNOMASK;
- have_expmask = -1;
- }
-#endif
+ int slot;
- printk("Installed expansion cards:");
+ oldlatch_init();
- /*
- * First of all, probe all cards on the expansion card interrupt line
- */
- for (i = 0; i < 8; i++)
- if (ecard_probe(i, nc, ECARD_IOC) || ecard_probe(i, nc, ECARD_EASI))
- nc += 1;
- else
- have_expmask &= ~(1<
+
.equ ioc_base_high, IOC_BASE & 0xff000000
.equ ioc_base_low, IOC_BASE & 0x00ff0000
.macro disable_fiq
@@ -186,113 +190,104 @@
.byte 6, 6, 6, 6, 2, 2, 2, 2, 3, 3, 6, 6, 2, 2, 2, 2
.endm
-#elif defined(CONFIG_ARCH_EBSA285)
+#elif defined(CONFIG_HOST_FOOTBRIDGE)
+#include
.macro disable_fiq
.endm
+ .equ irq_mask_pci_err_high, IRQ_MASK_PCI_ERR & 0xff000000
+ .equ irq_mask_pci_err_low, IRQ_MASK_PCI_ERR & 0x00ff0000
+
.macro get_irqnr_and_base, irqnr, irqstat, base
mov r4, #0xfe000000
ldr \irqstat, [r4, #0x180] @ get interrupts
- mov \irqnr, #0
-1001: tst \irqstat, #1
- addeq \irqnr, \irqnr, #1
- moveq \irqstat, \irqstat, lsr #1
- tsteq \irqnr, #32
- beq 1001b
- teq \irqnr, #32
- .endm
- .macro irq_prio_table
- .endm
+ tst \irqstat, #IRQ_MASK_SDRAMPARITY
+ movne \irqnr, #IRQ_SDRAMPARITY
+ bne 1001f
-#elif defined(CONFIG_ARCH_NEXUSPCI)
+ tst \irqstat, #IRQ_MASK_UART_RX
+ movne \irqnr, #IRQ_CONRX
+ bne 1001f
- .macro disable_fiq
- .endm
+ tst \irqstat, #IRQ_MASK_DMA1
+ movne \irqnr, #IRQ_DMA1
+ bne 1001f
- .macro get_irqnr_and_base, irqnr, irqstat, base
- ldr r4, =0xffe00000
- ldr \irqstat, [r4, #0x180] @ get interrupts
- mov \irqnr, #0
-1001: tst \irqstat, #1
- addeq \irqnr, \irqnr, #1
- moveq \irqstat, \irqstat, lsr #1
- tsteq \irqnr, #32
- beq 1001b
- teq \irqnr, #32
- .endm
+ tst \irqstat, #IRQ_MASK_DMA2
+ movne \irqnr, #IRQ_DMA2
+ bne 1001f
- .macro irq_prio_table
- .endm
+ tst \irqstat, #IRQ_MASK_IN0
+ movne \irqnr, #IRQ_IN0
+ bne 1001f
-#elif defined(CONFIG_ARCH_VNC)
+ tst \irqstat, #IRQ_MASK_IN1
+ movne \irqnr, #IRQ_IN1
+ bne 1001f
- .macro disable_fiq
- .endm
+ tst \irqstat, #IRQ_MASK_IN2
+ movne \irqnr, #IRQ_IN2
+ bne 1001f
- .equ pci_iack_high, PCI_IACK & 0xff000000
- .equ pci_iack_low, PCI_IACK & 0x00ff0000
+ tst \irqstat, #IRQ_MASK_IN3
+ movne \irqnr, #IRQ_IN3
+ bne 1001f
- .macro get_irqnr_and_base, irqnr, irqstat, base
- mov r4, #IO_BASE_ARM_CSR
- ldr \irqstat, [r4, #CSR_IRQ_STATUS] @ just show us the unmasked ones
+ tst \irqstat, #IRQ_MASK_PCI
+ movne \irqnr, #IRQ_PCI
+ bne 1001f
- @ run through hard priorities
- @ timer
- tst \irqstat, #IRQ_MASK_TIMER0
- movne \irqnr, #IRQ_TIMER0
+ tst \irqstat, #IRQ_MASK_I2OINPOST
+ movne \irqnr, #IRQ_I2OINPOST
bne 1001f
- @ ether10
- tst \irqstat, #IRQ_MASK_ETHER10
- movne \irqnr, #IRQ_ETHER10
+ tst \irqstat, #IRQ_MASK_TIMER1
+ movne \irqnr, #IRQ_TIMER1
bne 1001f
- @ ether100
- tst \irqstat, #IRQ_MASK_ETHER100
- movne \irqnr, #IRQ_ETHER100
+ tst \irqstat, #IRQ_MASK_TIMER2
+ movne \irqnr, #IRQ_TIMER2
bne 1001f
- @ video compressor
- tst \irqstat, #IRQ_MASK_VIDCOMP
- movne \irqnr, #IRQ_VIDCOMP
+ tst \irqstat, #IRQ_MASK_TIMER3
+ movne \irqnr, #IRQ_TIMER3
bne 1001f
- @ now try all the PIC sources
- @ determine whether we have an irq
- tst \irqstat, #IRQ_MASK_EXTERN_IRQ
- beq 1002f
- mov r4, #pci_iack_high
- orr r4, r4, #pci_iack_low
- ldrb \irqnr, [r4] @ get the IACK byte
- b 1001f
+ tst \irqstat, #IRQ_MASK_UART_TX
+ movne \irqnr, #IRQ_CONTX
+ bne 1001f
-1002: @ PCI errors
- tst \irqstat, #IRQ_MASK_PCI_ERR
+ tst \irqstat, #irq_mask_pci_err_high
+ tsteq \irqstat, #irq_mask_pci_err_low
movne \irqnr, #IRQ_PCI_ERR
bne 1001f
+1001:
+ .endm
- @ softint
- tst \irqstat, #IRQ_MASK_SOFTIRQ
- movne \irqnr, #IRQ_SOFTIRQ
- bne 1001f
+ .macro irq_prio_table
+ .endm
- @ debug uart
- tst \irqstat, #IRQ_MASK_UART_DEBUG
- movne \irqnr, #IRQ_CONRX
- bne 1001f
+#elif defined(CONFIG_ARCH_NEXUSPCI)
- @ watchdog
- tst \irqstat, #IRQ_MASK_WATCHDOG
- movne \irqnr, #IRQ_WATCHDOG
+ .macro disable_fiq
+ .endm
-1001: @ If Z is set, then we will not enter an interrupt
+ .macro get_irqnr_and_base, irqnr, irqstat, base
+ ldr r4, =0xffe00000
+ ldr \irqstat, [r4, #0x180] @ get interrupts
+ mov \irqnr, #0
+1001: tst \irqstat, #1
+ addeq \irqnr, \irqnr, #1
+ moveq \irqstat, \irqstat, lsr #1
+ tsteq \irqnr, #32
+ beq 1001b
+ teq \irqnr, #32
.endm
.macro irq_prio_table
.endm
-
#else
#error Unknown architecture
#endif
@@ -348,25 +343,6 @@
msr cpsr, \temp
.endm
- .macro initialise_traps_extra
- mrs r0, cpsr
- bic r0, r0, #31
- orr r0, r0, #0xd3
- msr cpsr, r0
- .endm
-
-
-#ifndef __ARM_ARCH_4__
-.Larm700bug: str lr, [r8]
- ldr r0, [sp, #S_PSR] @ Get calling cpsr
- msr spsr, r0
- ldmia sp, {r0 - lr}^ @ Get calling r0 - lr
- mov r0, r0
- add sp, sp, #S_PC
- ldr lr, [sp], #S_FRAME_SIZE - S_PC @ Get PC and jump over PC, PSR, OLD_R0
- movs pc, lr
-#endif
-
.macro get_current_task, rd
mov \rd, sp, lsr #13
mov \rd, \rd, lsl #13
@@ -379,231 +355,89 @@
adr\cond \reg, \label
.endm
-/*=============================================================================
- * Address exception handler
- *-----------------------------------------------------------------------------
- * These aren't too critical.
- * (they're not supposed to happen, and won't happen in 32-bit mode).
- */
-
-vector_addrexcptn:
- b vector_addrexcptn
-
-/*=============================================================================
- * Undefined FIQs
- *-----------------------------------------------------------------------------
- * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
- * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
- * Basically to switch modes, we *HAVE* to clobber one register... brain
- * damage alert! I don't think that we can execute any code in here in any
- * other mode than FIQ... Ok you can switch to another mode, but you can't
- * get out of that mode without clobbering one register.
- */
-_unexp_fiq: disable_fiq
- subs pc, lr, #4
-
-/*=============================================================================
- * Interrupt entry dispatcher
- *-----------------------------------------------------------------------------
- * Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
- */
-vector_IRQ: @
- @ save mode specific registers
- @
- ldr r13, .LCirq
- sub lr, lr, #4
- str lr, [r13] @ save lr_IRQ
- mrs lr, spsr
- str lr, [r13, #4] @ save spsr_IRQ
- @
- @ now branch to the relevent MODE handling routine
- @
- mrs sp, cpsr @ switch to SVC mode
- bic sp, sp, #31
- orr sp, sp, #0x13
- msr spsr, sp
- and lr, lr, #15
- cmp lr, #4
- addlts pc, pc, lr, lsl #2 @ Changes mode and branches
- b __irq_invalid @ 4 - 15
- b __irq_usr @ 0 (USR_26 / USR_32)
- b __irq_invalid @ 1 (FIQ_26 / FIQ_32)
- b __irq_invalid @ 2 (IRQ_26 / IRQ_32)
- b __irq_svc @ 3 (SVC_26 / SVC_32)
-/*
- *------------------------------------------------------------------------------------------------
- * Undef instr entry dispatcher - dispatches it to the correct handler for the processor mode
- *------------------------------------------------------------------------------------------------
- * Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
- */
-.LCirq: .word __temp_irq
-.LCund: .word __temp_und
-.LCabt: .word __temp_abt
-
-vector_undefinstr:
- @
- @ save mode specific registers
- @
- ldr r13, [pc, #.LCund - . - 8]
- str lr, [r13]
- mrs lr, spsr
- str lr, [r13, #4]
- @
- @ now branch to the relevent MODE handling routine
- @
- mrs sp, cpsr
- bic sp, sp, #31
- orr sp, sp, #0x13
- msr spsr, sp
- and lr, lr, #15
- cmp lr, #4
- addlts pc, pc, lr, lsl #2 @ Changes mode and branches
- b __und_invalid @ 4 - 15
- b __und_usr @ 0 (USR_26 / USR_32)
- b __und_invalid @ 1 (FIQ_26 / FIQ_32)
- b __und_invalid @ 2 (IRQ_26 / IRQ_32)
- b __und_svc @ 3 (SVC_26 / SVC_32)
-/*
- *------------------------------------------------------------------------------------------------
- * Prefetch abort dispatcher - dispatches it to the correct handler for the processor mode
- *------------------------------------------------------------------------------------------------
- * Enter in ABT mode, spsr = USR CPSR, lr = USR PC
- */
-vector_prefetch:
- @
- @ save mode specific registers
- @
- sub lr, lr, #4
- ldr r13, .LCabt
- str lr, [r13]
- mrs lr, spsr
- str lr, [r13, #4]
- @
- @ now branch to the relevent MODE handling routine
- @
- mrs sp, cpsr
- bic sp, sp, #31
- orr sp, sp, #0x13
- msr spsr, sp
- and lr, lr, #15
- adds pc, pc, lr, lsl #2 @ Changes mode and branches
- b __pabt_invalid @ 4 - 15
- b __pabt_usr @ 0 (USR_26 / USR_32)
- b __pabt_invalid @ 1 (FIQ_26 / FIQ_32)
- b __pabt_invalid @ 2 (IRQ_26 / IRQ_32)
- b __pabt_invalid @ 3 (SVC_26 / SVC_32)
/*
- *------------------------------------------------------------------------------------------------
- * Data abort dispatcher - dispatches it to the correct handler for the processor mode
- *------------------------------------------------------------------------------------------------
- * Enter in ABT mode, spsr = USR CPSR, lr = USR PC
+ * Invalid mode handlers
*/
-vector_data: @
- @ save mode specific registers
- @
- sub lr, lr, #8
- ldr r13, .LCabt
- str lr, [r13]
- mrs lr, spsr
- str lr, [r13, #4]
- @
- @ now branch to the relevent MODE handling routine
- @
- mrs sp, cpsr
- bic sp, sp, #31
- orr sp, sp, #0x13
- msr spsr, sp
- and lr, lr, #15
- cmp lr, #4
- addlts pc, pc, lr, lsl #2 @ Changes mode & branches
- b __dabt_invalid @ 4 - 15
- b __dabt_usr @ 0 (USR_26 / USR_32)
- b __dabt_invalid @ 1 (FIQ_26 / FIQ_32)
- b __dabt_invalid @ 2 (IRQ_26 / IRQ_32)
- b __dabt_svc @ 3 (SVC_26 / SVC_32)
+__pabt_invalid: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go
+ stmia sp, {r0 - lr} @ Save XXX r0 - lr
+ ldr r4, .LCabt
+ mov r1, #BAD_PREFETCH
+ b 1f
-/*=============================================================================
- * Prefetch abort handler
- *-----------------------------------------------------------------------------
- */
-pabtmsg: .ascii "Pabt: %08lX\n\0"
- .align
-__pabt_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go
- stmia sp, {r0 - r12} @ Save r0 - r12
- add r8, sp, #S_PC
- stmdb r8, {sp, lr}^ @ Save sp_usr lr_usr
+__dabt_invalid: sub sp, sp, #S_FRAME_SIZE
+ stmia sp, {r0 - lr} @ Save SVC r0 - lr [lr *should* be intact]
ldr r4, .LCabt
- ldmia r4, {r5 - r7} @ Get USR pc, cpsr
- stmia r8, {r5 - r7} @ Save USR pc, cpsr, old_r0
+ mov r1, #BAD_DATA
+ b 1f
- mrs r7, cpsr @ Enable interrupts if they were
- bic r7, r7, #I_BIT @ previously
- msr cpsr, r7
- mov r0, r5 @ address (pc)
- mov r1, sp @ regs
- bl SYMBOL_NAME(do_PrefetchAbort) @ call abort handler
- teq r0, #0 @ Does this still apply???
- bne ret_from_exception @ Return from exception
-#ifdef DEBUG_UNDEF
- adr r0, t
- bl SYMBOL_NAME(printk)
-#endif
- mov r0, r5
- mov r1, sp
- and r2, r6, #31
- bl SYMBOL_NAME(do_undefinstr)
- ldr lr, [sp, #S_PSR] @ Get USR cpsr
- msr spsr, lr
- ldmia sp, {r0 - pc}^ @ Restore USR registers
+__irq_invalid: sub sp, sp, #S_FRAME_SIZE @ Allocate space on stack for frame
+ stmfd sp, {r0 - lr} @ Save r0 - lr
+ ldr r4, .LCirq
+ mov r1, #BAD_IRQ
+ b 1f
-__pabt_invalid: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go
- stmia sp, {r0 - lr} @ Save XXX r0 - lr
- mov r7, r0 @ OLD R0
- ldr r4, .LCabt
- ldmia r4, {r5 - r7} @ Get XXX pc, cpsr
+__und_invalid: sub sp, sp, #S_FRAME_SIZE
+ stmia sp, {r0 - lr}
+ ldr r4, .LCund
+ mov r1, #BAD_UNDEFINSTR @ int reason
+
+1: mov fp, #0
+ ldmia r4, {r5 - r7} @ Get XXX pc, cpsr, old_r0
add r4, sp, #S_PC
stmia r4, {r5 - r7} @ Save XXX pc, cpsr, old_r0
- mov r0, sp @ Prefetch aborts are definitely *not*
- mov r1, #BAD_PREFETCH @ allowed in non-user modes. We cant
- and r2, r6, #31 @ recover from this problem.
+ mov r0, sp
+ and r2, r6, #31 @ int mode
b SYMBOL_NAME(bad_mode)
-#ifdef DEBUG_UNDEF
-t: .ascii "*** undef ***\r\n\0"
- .align
-#endif
-/*=============================================================================
- * Data abort handler code
- *-----------------------------------------------------------------------------
+wfs_mask_data: .word 0x0e200110 @ WFS/RFS
+ .word 0x0fef0fff
+ .word 0x0d0d0100 @ LDF [sp]/STF [sp]
+ .word 0x0d0b0100 @ LDF [fp]/STF [fp]
+ .word 0x0f0f0f00
+
+/* We get here if an undefined instruction happens and the floating
+ * point emulator is not present. If the offending instruction was
+ * a WFS, we just perform a normal return as if we had emulated the
+ * operation. This is a hack to allow some basic userland binaries
+ * to run so that the emulator module proper can be loaded. --philb
*/
-.LCprocfns: .word SYMBOL_NAME(processor)
+fpe_not_present:
+ adr r10, wfs_mask_data
+ ldmia r10, {r4, r5, r6, r7, r8}
+ ldr r10, [sp, #S_PC] @ Load PC
+ sub r10, r10, #-4
+ mask_pc r10, r10
+ ldrt r10, [r10] @ get instruction
+ and r5, r10, r5
+ teq r5, r4 @ Is it WFS?
+ moveq pc, r9
+ and r5, r10, r8
+ teq r5, r6 @ Is it LDF/STF on sp or fp?
+ teqne r5, r7
+ movne pc, lr
+ tst r10, #0x00200000 @ Does it have WB
+ moveq pc, r9
+ and r4, r10, #255 @ get offset
+ and r6, r10, #0x000f0000
+ tst r10, #0x00800000 @ +/-
+ rsbeq r4, r4, #0
+ ldr r5, [sp, r6, lsr #14] @ Load reg
+ add r5, r5, r4, lsl #2
+ str r5, [sp, r6, lsr #14] @ Save reg
+ mov pc, r9
-__dabt_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go
- stmia sp, {r0 - r12} @ save r0 - r12
- add r3, sp, #S_PC
- stmdb r3, {sp, lr}^
- ldr r0, .LCabt
- ldmia r0, {r0 - r2} @ Get USR pc, cpsr
- stmia r3, {r0 - r2} @ Save USR pc, cpsr, old_r0
- mov fp, #0
- mrs r2, cpsr @ Enable interrupts if they were
- bic r2, r2, #I_BIT @ previously
- msr cpsr, r2
- ldr r2, .LCprocfns
- mov lr, pc
- ldr pc, [r2, #8] @ call processor specific code
- mov r3, sp
- bl SYMBOL_NAME(do_DataAbort)
- b ret_from_sys_call
-
-__dabt_svc: sub sp, sp, #S_FRAME_SIZE
+/*
+ * SVC mode handlers
+ */
+ .align 5
+__dabt_svc: sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ save r0 - r12
ldr r2, .LCabt
add r0, sp, #S_FRAME_SIZE
+ ldmia r2, {r2 - r4} @ get pc, cpsr
add r5, sp, #S_SP
mov r1, lr
- ldmia r2, {r2 - r4} @ get pc, cpsr
stmia r5, {r0 - r4} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro
tst r3, #I_BIT
mrseq r0, cpsr @ Enable interrupts if they were
@@ -619,29 +453,15 @@
msr spsr, r0
ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
-__dabt_invalid: sub sp, sp, #S_FRAME_SIZE
- stmia sp, {r0 - lr} @ Save SVC r0 - lr [lr *should* be intact]
- mov r7, r0
- ldr r4, .LCabt
- ldmia r4, {r5, r6} @ Get SVC pc, cpsr
- add r4, sp, #S_PC
- stmia r4, {r5, r6, r7} @ Save SVC pc, cpsr, old_r0
- mov r0, sp
- mov r1, #BAD_DATA
- and r2, r6, #31
- b SYMBOL_NAME(bad_mode)
-
-/*=============================================================================
- * Interrupt (IRQ) handler
- *-----------------------------------------------------------------------------
- */
-__irq_usr: sub sp, sp, #S_FRAME_SIZE
+ .align 5
+__irq_svc: sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ save r0 - r12
- add r8, sp, #S_PC
- stmdb r8, {sp, lr}^
- ldr r4, .LCirq
- ldmia r4, {r5 - r7} @ get saved PC, SPSR
- stmia r8, {r5 - r7} @ save pc, psr, old_r0
+ ldr r7, .LCirq
+ add r5, sp, #S_FRAME_SIZE
+ ldmia r7, {r7 - r9}
+ add r4, sp, #S_SP
+ mov r6, lr
+ stmia r4, {r5, r6, r7, r8, r9} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro
1: get_irqnr_and_base r0, r6, r5
movne r1, sp
@
@@ -649,48 +469,97 @@
@
adrsvc ne, lr, 1b
bne do_IRQ
- b ret_with_reschedule
-
- irq_prio_table
+ ldr r0, [sp, #S_PSR]
+ msr spsr, r0
+ ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
-__irq_svc: sub sp, sp, #S_FRAME_SIZE
+ .align 5
+__und_svc: sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ save r0 - r12
mov r6, lr
- ldr r7, .LCirq
+ ldr r7, .LCund
ldmia r7, {r7 - r9}
add r5, sp, #S_FRAME_SIZE
add r4, sp, #S_SP
- stmia r4, {r5, r6, r7, r8, r9} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro
+ stmia r4, {r5 - r9} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro
+
+ adrsvc al, r9, 1f @ r9 = normal FP return
+ bl call_fpe @ lr = undefined instr return
+
+ mov r0, r5 @ unsigned long pc
+ mov r1, sp @ struct pt_regs *regs
+ bl SYMBOL_NAME(do_undefinstr)
+
+1: ldr lr, [sp, #S_PSR] @ Get SVC cpsr
+ msr spsr, lr
+ ldmia sp, {r0 - pc}^ @ Restore SVC registers
+
+ .align 5
+.LCirq: .word __temp_irq
+.LCund: .word __temp_und
+.LCabt: .word __temp_abt
+.LCprocfns: .word SYMBOL_NAME(processor)
+.LCfp: .word SYMBOL_NAME(fp_enter)
+
+ irq_prio_table
+
+/*
+ * User mode handlers
+ */
+#ifdef DEBUG_UNDEF
+t: .ascii "Prefetch -> undefined instruction\n\0"
+ .align
+#endif
+ .align 5
+__dabt_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go
+ stmia sp, {r0 - r12} @ save r0 - r12
+ add r3, sp, #S_PC
+ stmdb r3, {sp, lr}^
+ ldr r4, .LCabt
+ ldmia r4, {r0 - r2} @ Get USR pc, cpsr
+ stmia r3, {r0 - r2} @ Save USR pc, cpsr, old_r0
+
+#ifdef CONFIG_ALIGNMENT_TRAP
+ ldr r7, [r4, #OFF_CR_ALIGNMENT(__temp_abt)]
+ mcr p15, 0, r7, c1, c0
+#endif
+
+ mov fp, #0
+ mrs r2, cpsr @ Enable interrupts if they were
+ bic r2, r2, #I_BIT @ previously
+ msr cpsr, r2
+ ldr r2, .LCprocfns
+ mov lr, pc
+ ldr pc, [r2, #8] @ call processor specific code
+ mov r3, sp
+ adrsvc al, lr, ret_from_sys_call
+ b SYMBOL_NAME(do_DataAbort)
+
+ .align 5
+__irq_usr: sub sp, sp, #S_FRAME_SIZE
+ stmia sp, {r0 - r12} @ save r0 - r12
+ add r8, sp, #S_PC
+ stmdb r8, {sp, lr}^
+ ldr r4, .LCirq
+ ldmia r4, {r5 - r7} @ get saved PC, SPSR
+ stmia r8, {r5 - r7} @ save pc, psr, old_r0
+
+#ifdef CONFIG_ALIGNMENT_TRAP
+ ldr r7, [r4, #OFF_CR_ALIGNMENT(__temp_irq)]
+ mcr p15, 0, r7, c1, c0
+#endif
+
1: get_irqnr_and_base r0, r6, r5
movne r1, sp
+ adrsvc ne, lr, 1b
@
@ routine called with r0 = irq number, r1 = struct pt_regs *
@
- adrsvc ne, lr, 1b
bne do_IRQ
- ldr r0, [sp, #S_PSR]
- msr spsr, r0
- ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
-
-__irq_invalid: sub sp, sp, #S_FRAME_SIZE @ Allocate space on stack for frame
- stmfd sp, {r0 - lr} @ Save r0 - lr
- mov r7, #-1
- ldr r4, .LCirq
- ldmia r4, {r5, r6} @ get saved pc, psr
- add r4, sp, #S_PC
- stmia r4, {r5, r6, r7}
- mov fp, #0
- mov r0, sp
- mov r1, #BAD_IRQ
- b SYMBOL_NAME(bad_mode)
-
-/*=============================================================================
- * Undefined instruction handler
- *-----------------------------------------------------------------------------
- * Handles floating point instructions
- */
-.LC2: .word SYMBOL_NAME(fp_enter)
+ mov r4, #0
+ b ret_with_reschedule
+ .align 5
__und_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go
stmia sp, {r0 - r12} @ Save r0 - r12
add r8, sp, #S_PC
@@ -698,99 +567,311 @@
ldr r4, .LCund
ldmia r4, {r5 - r7}
stmia r8, {r5 - r7} @ Save USR pc, cpsr, old_r0
+
+#ifdef CONFIG_ALIGNMENT_TRAP
+ ldr r7, [r4, #OFF_CR_ALIGNMENT(__temp_und)]
+ mcr p15, 0, r7, c1, c0
+#endif
+
mov fp, #0
- adrsvc al, r9, ret_from_exception @ r9 = normal FP return
+ adrsvc al, r9, ret_from_sys_call @ r9 = normal FP return
adrsvc al, lr, fpundefinstr @ lr = undefined instr return
-1: get_current_task r10
+call_fpe: get_current_task r10
mov r8, #1
strb r8, [r10, #TSK_USED_MATH] @ set current->used_math
add r10, r10, #TSS_FPESAVE @ r10 = workspace
- ldr r4, .LC2
+ ldr r4, .LCfp
ldr pc, [r4] @ Call FP module USR entry point
-__und_svc: sub sp, sp, #S_FRAME_SIZE
- stmia sp, {r0 - r12} @ save r0 - r12
- mov r6, lr
- ldr r7, .LCund
- ldmia r7, {r7 - r9}
- add r5, sp, #S_FRAME_SIZE
- add r4, sp, #S_SP
- stmia r4, {r5 - r9} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro
-
- adrsvc al, r9, 3f @ r9 = normal FP return
- bl 1b @ lr = undefined instr return
-
- mov r0, r5 @ unsigned long pc
- mov r1, sp @ struct pt_regs *regs
- bl SYMBOL_NAME(do_undefinstr)
-
-3: ldr lr, [sp, #S_PSR] @ Get SVC cpsr
- msr spsr, lr
- ldmia sp, {r0 - pc}^ @ Restore SVC registers
-
fpundefinstr: mov r0, lr
mov r1, sp
mrs r4, cpsr @ Enable interrupts
bic r4, r4, #I_BIT
msr cpsr, r4
- adrsvc al, lr, ret_from_exception
+ adrsvc al, lr, ret_from_sys_call
b SYMBOL_NAME(do_undefinstr)
-__und_invalid: sub sp, sp, #S_FRAME_SIZE
- stmia sp, {r0 - lr}
- mov r7, r0
- ldr r4, .LCund
- ldmia r4, {r5, r6} @ Get UND/IRQ/FIQ/ABT pc, cpsr
- add r4, sp, #S_PC
- stmia r4, {r5, r6, r7} @ Save UND/IRQ/FIQ/ABT pc, cpsr, old_r0
- mov r0, sp @ struct pt_regs *regs
- mov r1, #BAD_UNDEFINSTR @ int reason
- and r2, r6, #31 @ int mode
- b SYMBOL_NAME(bad_mode) @ Does not ever return...
+ .align 5
+__pabt_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go
+ stmia sp, {r0 - r12} @ Save r0 - r12
+ add r8, sp, #S_PC
+ stmdb r8, {sp, lr}^ @ Save sp_usr lr_usr
+ ldr r4, .LCabt
+ ldmia r4, {r5 - r7} @ Get USR pc, cpsr
+ stmia r8, {r5 - r7} @ Save USR pc, cpsr, old_r0
-/* We get here if an undefined instruction happens and the floating
- * point emulator is not present. If the offending instruction was
- * a WFS, we just perform a normal return as if we had emulated the
- * operation. This is a hack to allow some basic userland binaries
- * to run so that the emulator module proper can be loaded. --philb
- */
-fpe_not_present:
- adr r10, wfs_mask_data
- ldmia r10, {r4, r5, r6, r7, r8}
- ldr r10, [sp, #S_PC] @ Load PC
- sub r10, r10, #4
- mask_pc r10, r10
- ldrt r10, [r10] @ get instruction
- and r5, r10, r5
- teq r5, r4 @ Is it WFS?
- moveq pc, r9
- and r5, r10, r8
- teq r5, r6 @ Is it LDF/STF on sp or fp?
- teqne r5, r7
- movne pc, lr
- tst r10, #0x00200000 @ Does it have WB
- moveq pc, r9
- and r4, r10, #255 @ get offset
- and r6, r10, #0x000f0000
- tst r10, #0x00800000 @ +/-
- rsbeq r4, r4, #0
- ldr r5, [sp, r6, lsr #14] @ Load reg
- add r5, r5, r4, lsl #2
- str r5, [sp, r6, lsr #14] @ Save reg
- mov pc, r9
+#ifdef CONFIG_ALIGNMENT_TRAP
+ ldr r7, [r4, #OFF_CR_ALIGNMENT(__temp_abt)]
+ mcr p15, 0, r7, c1, c0
+#endif
-wfs_mask_data: .word 0x0e200110 @ WFS
- .word 0x0fff0fff
- .word 0x0d0d0100 @ LDF [sp]/STF [sp]
- .word 0x0d0b0100 @ LDF [fp]/STF [fp]
- .word 0x0f0f0f00
+ mrs r7, cpsr @ Enable interrupts if they were
+ bic r7, r7, #I_BIT @ previously
+ msr cpsr, r7
+ mov r0, r5 @ address (pc)
+ mov r1, sp @ regs
+ bl SYMBOL_NAME(do_PrefetchAbort) @ call abort handler
+ teq r0, #0 @ Does this still apply???
+ bne ret_from_sys_call @ Return from exception
+#ifdef DEBUG_UNDEF
+ adr r0, t
+ bl SYMBOL_NAME(printk)
+#endif
+ mov r0, r5
+ mov r1, sp
+ and r2, r6, #31
+ bl SYMBOL_NAME(do_undefinstr)
+ ldr lr, [sp, #S_PSR] @ Get USR cpsr
+ msr spsr, lr
+ ldmia sp, {r0 - pc}^ @ Restore USR registers
#include "entry-common.S"
+ .text
+
+#ifndef __ARM_ARCH_4__
+.Larm700bug: str lr, [r8]
+ ldr r0, [sp, #S_PSR] @ Get calling cpsr
+ msr spsr, r0
+ ldmia sp, {r0 - lr}^ @ Get calling r0 - lr
+ mov r0, r0
+ add sp, sp, #S_PC
+ ldr lr, [sp], #S_FRAME_SIZE - S_PC @ Get PC and jump over PC, PSR, OLD_R0
+ movs pc, lr
+#endif
+
+ .section ".text.init",#alloc,#execinstr
+/*
+ * Vector stubs. NOTE that we only align 'vector_IRQ' to a cache line boundary,
+ * and we rely on each stub being exactly 48 (1.5 cache lines) in size. This
+ * means that we only ever load two cache lines for this code, or one if we're
+ * lucky. We also copy this code to 0x200 so that we can use branches in the
+ * vectors, rather than ldr's.
+ */
+ .align 5
+__stubs_start:
+/*
+ * Interrupt dispatcher
+ * Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
+ */
+vector_IRQ: @
+ @ save mode specific registers
+ @
+ ldr r13, .LCsirq
+ sub lr, lr, #4
+ str lr, [r13] @ save lr_IRQ
+ mrs lr, spsr
+ str lr, [r13, #4] @ save spsr_IRQ
+ @
+ @ now branch to the relevent MODE handling routine
+ @
+ bic r13, lr, #63
+ orr r13, r13, #0x93
+ msr spsr, r13 @ switch to SVC_32 mode
+
+ and lr, lr, #15
+ adr r13, .LCtab_irq
+ ldr lr, [r13, lr, lsl #2]
+ movs pc, lr @ Changes mode and branches
+/*
+ * Data abort dispatcher - dispatches it to the correct handler for the processor mode
+ * Enter in ABT mode, spsr = USR CPSR, lr = USR PC
+ */
+vector_data: @
+ @ save mode specific registers
+ @
+ sub lr, lr, #8
+ ldr r13, .LCsabt
+ str lr, [r13]
+ mrs lr, spsr
+ str lr, [r13, #4]
+ @
+ @ now branch to the relevent MODE handling routine
+ @
+ bic r13, lr, #63
+ orr r13, r13, #0x93
+ msr spsr, r13 @ switch to SVC_32 mode
+
+ and lr, lr, #15
+ adr r13, .LCtab_dabt
+ ldr lr, [r13, lr, lsl #2]
+ movs pc, lr @ Changes mode and branches
+
+/*
+ * Prefetch abort dispatcher - dispatches it to the correct handler for the processor mode
+ * Enter in ABT mode, spsr = USR CPSR, lr = USR PC
+ */
+vector_prefetch:
+ @
+ @ save mode specific registers
+ @
+ sub lr, lr, #4
+ ldr r13, .LCsabt
+ str lr, [r13] @ save lr_ABT
+ mrs lr, spsr
+ str lr, [r13, #4] @ save spsr_ABT
+ @
+ @ now branch to the relevent MODE handling routine
+ @
+ bic r13, lr, #63
+ orr r13, r13, #0x93
+ msr spsr, r13 @ switch to SVC_32 mode
+
+ ands lr, lr, #15
+ ldreq lr, .LCtab_pabt
+ ldrne lr, .LCtab_pabt + 4
+ movs pc, lr
+
+/*
+ * Undef instr entry dispatcher - dispatches it to the correct handler for the processor mode
+ * Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
+ */
+vector_undefinstr:
+ @
+ @ save mode specific registers
+ @
+ ldr r13, .LCsund
+ str lr, [r13] @ save lr_UND
+ mrs lr, spsr
+ str lr, [r13, #4] @ save spsr_UND
+ @
+ @ now branch to the relevent MODE handling routine
+ @
+ bic r13, lr, #63
+ orr r13, r13, #0x93
+ msr spsr, r13 @ switch to SVC_32 mode
+
+ and lr, lr, #15
+ adr r13, .LCtab_und
+ ldr lr, [r13, lr, lsl #2]
+ movs pc, lr @ Changes mode and branches
+
+/*=============================================================================
+ * Undefined FIQs
+ *-----------------------------------------------------------------------------
+ * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
+ * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
+ * Basically to switch modes, we *HAVE* to clobber one register... brain
+ * damage alert! I don't think that we can execute any code in here in any
+ * other mode than FIQ... Ok you can switch to another mode, but you can't
+ * get out of that mode without clobbering one register.
+ */
+vector_FIQ: disable_fiq
+ subs pc, lr, #4
+
+/*=============================================================================
+ * Address exception handler
+ *-----------------------------------------------------------------------------
+ * These aren't too critical.
+ * (they're not supposed to happen, and won't happen in 32-bit data mode).
+ */
+
+vector_addrexcptn:
+ b vector_addrexcptn
+
+/*
+ * We group all the following data together to optimise
+ * for CPUs with separate I & D caches.
+ */
+ .align 5
+
+.LCtab_irq: .word __irq_usr @ 0 (USR_26 / USR_32)
+ .word __irq_invalid @ 1 (FIQ_26 / FIQ_32)
+ .word __irq_invalid @ 2 (IRQ_26 / IRQ_32)
+ .word __irq_svc @ 3 (SVC_26 / SVC_32)
+ .word __irq_invalid @ 4
+ .word __irq_invalid @ 5
+ .word __irq_invalid @ 6
+ .word __irq_invalid @ 7
+ .word __irq_invalid @ 8
+ .word __irq_invalid @ 9
+ .word __irq_invalid @ a
+ .word __irq_invalid @ b
+ .word __irq_invalid @ c
+ .word __irq_invalid @ d
+ .word __irq_invalid @ e
+ .word __irq_invalid @ f
+
+.LCtab_und: .word __und_usr @ 0 (USR_26 / USR_32)
+ .word __und_invalid @ 1 (FIQ_26 / FIQ_32)
+ .word __und_invalid @ 2 (IRQ_26 / IRQ_32)
+ .word __und_svc @ 3 (SVC_26 / SVC_32)
+ .word __und_invalid @ 4
+ .word __und_invalid @ 5
+ .word __und_invalid @ 6
+ .word __und_invalid @ 7
+ .word __und_invalid @ 8
+ .word __und_invalid @ 9
+ .word __und_invalid @ a
+ .word __und_invalid @ b
+ .word __und_invalid @ c
+ .word __und_invalid @ d
+ .word __und_invalid @ e
+ .word __und_invalid @ f
+
+.LCtab_dabt: .word __dabt_usr @ 0 (USR_26 / USR_32)
+ .word __dabt_invalid @ 1 (FIQ_26 / FIQ_32)
+ .word __dabt_invalid @ 2 (IRQ_26 / IRQ_32)
+ .word __dabt_svc @ 3 (SVC_26 / SVC_32)
+ .word __dabt_invalid @ 4
+ .word __dabt_invalid @ 5
+ .word __dabt_invalid @ 6
+ .word __dabt_invalid @ 7
+ .word __dabt_invalid @ 8
+ .word __dabt_invalid @ 9
+ .word __dabt_invalid @ a
+ .word __dabt_invalid @ b
+ .word __dabt_invalid @ c
+ .word __dabt_invalid @ d
+ .word __dabt_invalid @ e
+ .word __dabt_invalid @ f
+
+.LCtab_pabt: .word __pabt_usr
+ .word __pabt_invalid
+
+.LCvswi: .word vector_swi
+
+.LCsirq: .word __temp_irq
+.LCsund: .word __temp_und
+.LCsabt: .word __temp_abt
+
+__stubs_end:
+
+ .equ __real_stubs_start, .LCvectors + 0x200
+
+.LCvectors: swi SYS_ERROR0
+ b __real_stubs_start + (vector_undefinstr - __stubs_start)
+ ldr pc, __real_stubs_start + (.LCvswi - __stubs_start)
+ b __real_stubs_start + (vector_prefetch - __stubs_start)
+ b __real_stubs_start + (vector_data - __stubs_start)
+ b __real_stubs_start + (vector_addrexcptn - __stubs_start)
+ b __real_stubs_start + (vector_IRQ - __stubs_start)
+ b __real_stubs_start + (vector_FIQ - __stubs_start)
+
+ENTRY(trap_init)
+ stmfd sp!, {r4 - r6, lr}
+ adr r0, __stubs_start @ copy stubs to 0x200
+ adr r1, __stubs_end
+ mov r2, #0x200
+1: ldr r3, [r0], #4
+ str r3, [r2], #4
+ cmp r0, r1
+ blt 1b
+
+ adr r1, .LCvectors @ set up the vectors
+ mov r0, #0
+ ldmia r1, {r1, r2, r3, r4, r5, r6, ip, lr}
+ stmia r0, {r1, r2, r3, r4, r5, r6, ip, lr}
+ LOADREGS(fd, sp!, {r4 - r6, pc})
+
.data
+/*
+ * Do not reorder these, and do not insert extra data between...
+ */
+
__temp_irq: .word 0 @ saved lr_irq
.word 0 @ saved spsr_irq
.word -1 @ old_r0
@@ -800,3 +881,10 @@
__temp_abt: .word 0 @ Saved lr_abt
.word 0 @ Saved spsr_abt
.word -1 @ old_r0
+
+ .globl SYMBOL_NAME(cr_alignment)
+ .globl SYMBOL_NAME(cr_no_alignment)
+SYMBOL_NAME(cr_alignment):
+ .space 4
+SYMBOL_NAME(cr_no_alignment):
+ .space 4
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/entry-common.S linux.ac/arch/arm/kernel/entry-common.S
--- linux.vanilla/arch/arm/kernel/entry-common.S Tue Dec 22 23:19:26 1998
+++ linux.ac/arch/arm/kernel/entry-common.S Mon Feb 22 21:50:54 1999
@@ -1,51 +1,56 @@
+#include
+
/*============================================================================
* All exits to user mode from the kernel go through this code.
*/
-
-#include
-
.globl ret_from_sys_call
-ret_from_exception:
- adr r0, 1f
- ldmia r0, {r0, r1}
+ .align 5
+fast_syscall_return:
+ str r0, [sp, #S_R0 + 4] @ returned r0
+slow_syscall_return:
+ add sp, sp, #4
+ret_from_sys_call:
+ adr r0, bh_data
+ ldmia r0, {r0, r4}
ldr r0, [r0]
- ldr r1, [r1]
+ ldr r1, [r4]
tst r0, r1
blne SYMBOL_NAME(do_bottom_half)
-ret_from_intr: ldr r0, [sp, #S_PSR]
- tst r0, #3
- beq ret_with_reschedule
- b ret_from_all
+ret_with_reschedule:
+ get_current_task r1 @ check for scheduling
+ ldr r0, [r1, #TSK_NEED_RESCHED]
+ teq r0, #0
+ bne ret_reschedule
+ ldr r1, [r1, #TSK_SIGPENDING]
+ teq r1, #0 @ check for signals
+ bne ret_signal
+
+ret_from_all: restore_user_regs
ret_signal: mov r1, sp
adrsvc al, lr, ret_from_all
+ mov r2, r4
b SYMBOL_NAME(do_signal)
-2: bl SYMBOL_NAME(schedule)
+ret_reschedule: adrsvc al, lr, ret_with_reschedule
+ b SYMBOL_NAME(schedule)
-ret_from_sys_call:
- adr r0, 1f
+ .globl ret_from_exception
+ret_from_exception:
+ adr r0, bh_data
ldmia r0, {r0, r1}
ldr r0, [r0]
ldr r1, [r1]
tst r0, r1
- adrsvc ne, lr, ret_from_intr
- bne SYMBOL_NAME(do_bottom_half)
-
-ret_with_reschedule:
- get_current_task r1
- ldr r0, [r1, #TSK_NEED_RESCHED]
- teq r0, #0
- bne 2b
- ldr r1, [r1, #TSK_SIGPENDING]
- teq r1, #0
- bne ret_signal
-
-ret_from_all: restore_user_regs
+ mov r4, #0
+ blne SYMBOL_NAME(do_bottom_half)
+ ldr r0, [sp, #S_PSR]
+ tst r0, #3 @ returning to user mode?
+ beq ret_with_reschedule
+ b ret_from_all
-1: .word SYMBOL_NAME(bh_mask)
- .word SYMBOL_NAME(bh_active)
+#include "calls.S"
/*=============================================================================
* SWI handler
@@ -57,84 +62,61 @@
* too worried.
*/
-#include "calls.S"
-
+ .align 5
vector_swi: save_user_regs
- mov fp, #0
mask_pc lr, lr
- ldr r6, [lr, #-4]! @ get SWI instruction
+ mov fp, #0
+ ldr r6, [lr, #-4] @ get SWI instruction
arm700_bug_check r6, r7
enable_irqs r7
-
+
+ str r4, [sp, #-4]! @ new style: (r0 = arg1, r4 = arg5)
+ adrsvc al, lr, fast_syscall_return
+
bic r6, r6, #0xff000000 @ mask off SWI op-code
eor r6, r6, #OS_NUMBER<<20 @ check OS number
cmp r6, #NR_syscalls @ check upper syscall limit
bcs 2f
- get_current_task r5
- ldr ip, [r5, #TSK_FLAGS] @ check for syscall tracing
- tst ip, #PF_TRACESYS
- bne 1f
+ adr r5, SYMBOL_NAME(sys_call_table)
- adr ip, SYMBOL_NAME(sys_call_table)
- str r4, [sp, #-4]! @ new style: (r0 = arg1, r5 = arg5)
- mov lr, pc
- ldr pc, [ip, r6, lsl #2] @ call sys routine
- add sp, sp, #4
- str r0, [sp, #S_R0] @ returned r0
- b ret_from_sys_call
+ get_current_task r7
+ ldr ip, [r7, #TSK_FLAGS] @ check for syscall tracing
+ tst ip, #PF_TRACESYS
+ ldreq pc, [r5, r6, lsl #2] @ call sys routine
-1: ldr r7, [sp, #S_IP] @ save old IP
+ ldr r7, [sp, #S_IP + 4] @ save old IP
mov r0, #0
- str r0, [sp, #S_IP] @ trace entry [IP = 0]
+ str r0, [sp, #S_IP + 4] @ trace entry [IP = 0]
bl SYMBOL_NAME(syscall_trace)
- str r7, [sp, #S_IP]
- ldmia sp, {r0 - r3} @ have to reload r0 - r3
- adr ip, SYMBOL_NAME(sys_call_table)
- str r4, [sp, #-4]! @ new style: (r0 = arg1, r5 = arg5)
+ str r7, [sp, #S_IP + 4]
+
+ ldmib sp, {r0 - r3} @ have to reload r0 - r3
mov lr, pc
- ldr pc, [ip, r6, lsl #2] @ call sys routine
- add sp, sp, #4
- str r0, [sp, #S_R0] @ returned r0
+ ldr pc, [r5, r6, lsl #2] @ call sys routine
+ str r0, [sp, #S_R0 + 4] @ returned r0
+
mov r0, #1
- str r0, [sp, #S_IP] @ trace exit [IP = 1]
+ str r0, [sp, #S_IP + 4] @ trace exit [IP = 1]
bl SYMBOL_NAME(syscall_trace)
- str r7, [sp, #S_IP]
- b ret_from_sys_call
+ str r7, [sp, #S_IP + 4]
+ b slow_syscall_return
-2: tst r6, #0x00f00000 @ is it a Unix SWI?
+2: add r1, sp, #4
+ tst r6, #0x00f00000 @ is it a Unix SWI?
bne 3f
- cmp r6, #(KSWI_SYS_BASE - KSWI_BASE)
- bcc 4f @ not private func
- bic r0, r6, #0x000f0000
- mov r1, sp
- bl SYMBOL_NAME(arm_syscall)
- b ret_from_sys_call
-
-3: eor r0, r6, #OS_NUMBER<<20 @ Put OS number back
- mov r1, sp
- bl SYMBOL_NAME(deferred)
- ldmfd sp, {r0 - r3}
- b ret_from_sys_call
-
-4: bl SYMBOL_NAME(sys_ni_syscall)
- str r0, [sp, #0] @ returned r0
- b ret_from_sys_call
+ subs r0, r6, #(KSWI_SYS_BASE - KSWI_BASE)
+ bcs SYMBOL_NAME(arm_syscall)
+ b SYMBOL_NAME(sys_ni_syscall) @ not private func
-@ r0 = syscall number
-@ r1 = syscall r0
-@ r5 = syscall r4
-@ ip = syscall table
-SYMBOL_NAME(sys_syscall):
- mov r6, r0
- eor r6, r6, #OS_NUMBER << 20
- cmp r6, #NR_syscalls @ check range
- movgt r0, #-ENOSYS
- movgt pc, lr
- add sp, sp, #4 @ take of the save of our r4
- ldmib sp, {r0 - r4} @ get our args
- str r4, [sp, #-4]! @ Put our arg on the stack
- ldr pc, [ip, r6, lsl #2]
+3: eor r0, r6, #OS_NUMBER <<20 @ Put OS number back
+ adrsvc al, lr, slow_syscall_return
+ b SYMBOL_NAME(deferred)
+
+ .align 5
+
+bh_data: .word SYMBOL_NAME(bh_mask)
+ .word SYMBOL_NAME(bh_active)
ENTRY(sys_call_table)
#include "calls.S"
@@ -142,10 +124,25 @@
/*============================================================================
* Special system call wrappers
*/
+@ r0 = syscall number
+@ r5 = syscall table
+SYMBOL_NAME(sys_syscall):
+ eor r6, r0, #OS_NUMBER << 20
+ cmp r6, #NR_syscalls @ check range
+ ldmleib sp, {r0 - r4} @ get our args
+ strle r4, [sp] @ Put our arg on the stack
+ ldrle pc, [r5, r6, lsl #2]
+ mov r0, #-ENOSYS
+ mov pc, lr
+
sys_fork_wrapper:
add r0, sp, #4
b SYMBOL_NAME(sys_fork)
+sys_vfork_wrapper:
+ add r0, sp, #4
+ b SYMBOL_NAME(sys_vfork)
+
sys_execve_wrapper:
add r3, sp, #4
b SYMBOL_NAME(sys_execve)
@@ -191,99 +188,6 @@
sys_sigaltstack_wrapper:
ldr r2, [sp, #4 + S_SP]
b do_sigaltstack
-
-/*
- *=============================================================================
- * Low-level interface code
- *-----------------------------------------------------------------------------
- * Trap initialisation
- *-----------------------------------------------------------------------------
- *
- * Note - FIQ code has changed. The default is a couple of words in 0x1c, 0x20
- * that call _unexp_fiq. Nowever, we now copy the FIQ routine to 0x1c (removes
- * some excess cycles).
- *
- * What we need to put into 0-0x1c are ldrs to branch to 0xC0000000
- * (the kernel).
- * 0x1c onwards is reserved for FIQ, so I think that I will allocate 0xe0 onwards for
- * the actual address to jump to.
- */
-
- .section ".text.init",#alloc,#execinstr
-
-#if defined(CONFIG_CPU_32)
-/*
- * these go into 0x00
- */
-.Lbranches: swi SYS_ERROR0
- ldr pc, .Lbranches + 0xe4
- ldr pc, .Lbranches + 0xe8
- ldr pc, .Lbranches + 0xec
- ldr pc, .Lbranches + 0xf0
- ldr pc, .Lbranches + 0xf4
- ldr pc, .Lbranches + 0xf8
- ldr pc, .Lbranches + 0xfc
-/*
- * this is put into 0xe4 and above
- */
-.Ljump_addresses:
- .word vector_undefinstr @ 0xe4
- .word vector_swi @ 0xe8
- .word vector_prefetch @ 0xec
- .word vector_data @ 0xf0
- .word vector_addrexcptn @ 0xf4
- .word vector_IRQ @ 0xf8
- .word _unexp_fiq @ 0xfc
-/*
- * initialise the trap system
- */
-ENTRY(trap_init)
- stmfd sp!, {r4 - r7, lr}
- initialise_traps_extra
- mov r0, #0xe4
- adr r1, .Ljump_addresses
- ldmia r1, {r1 - r7}
- stmia r0, {r1 - r7}
- mov r0, #0
- adr r1, .Lbranches
- ldmia r1, {r1 - r7}
- stmia r0, {r1 - r7}
- LOADREGS(fd, sp!, {r4 - r7, pc})
-#elif defined(CONFIG_CPU_26)
-.Ljump_addresses:
- swi SYS_ERROR0
- .word vector_undefinstr - 12
- .word vector_swi - 16
- .word vector_prefetch - 20
- .word vector_data - 24
- .word vector_addrexcptn - 28
- .word vector_IRQ - 32
- .word _unexp_fiq - 36
- b . + 8
-/*
- * initialise the trap system
- */
-ENTRY(trap_init)
- stmfd sp!, {r4 - r7, lr}
- adr r1, .Ljump_addresses
- ldmia r1, {r1 - r7, ip, lr}
- orr r2, lr, r2, lsr #2
- orr r3, lr, r3, lsr #2
- orr r4, lr, r4, lsr #2
- orr r5, lr, r5, lsr #2
- orr r6, lr, r6, lsr #2
- orr r7, lr, r7, lsr #2
- orr ip, lr, ip, lsr #2
- mov r0, #0
- stmia r0, {r1 - r7, ip}
- ldmfd sp!, {r4 - r7, pc}^
-#endif
-
- .previous
-
-/*============================================================================
- * FP support
- */
.data
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/fiq.c linux.ac/arch/arm/kernel/fiq.c
--- linux.vanilla/arch/arm/kernel/fiq.c Tue Dec 22 23:19:26 1998
+++ linux.ac/arch/arm/kernel/fiq.c Tue Feb 2 20:27:00 1999
@@ -2,6 +2,8 @@
* linux/arch/arm/kernel/fiq.c
*
* Copyright (C) 1998 Russell King
+ * Copyright (C) 1998, 1999 Phil Blundell
+ *
* FIQ support written by Philip Blundell , 1998.
*
* FIQ support re-written by Russell King to be more generic
@@ -111,23 +113,74 @@
#endif
}
+/*
+ * Taking an interrupt in FIQ mode is death, so both these functions
+ * disable irqs for the duration.
+ */
void set_fiq_regs(struct pt_regs *regs)
{
- /* not yet -
- * this is temporary to get the floppy working
- * again on RiscPC. It *will* become more
- * generic.
- */
-#ifdef CONFIG_ARCH_ACORN
- extern void floppy_fiqsetup(unsigned long len, unsigned long addr,
- unsigned long port);
- floppy_fiqsetup(regs->ARM_r9, regs->ARM_r10, regs->ARM_fp);
+ register unsigned long tmp, tmp2;
+ __asm__ volatile (
+#ifdef CONFIG_CPU_26
+ "mov %0, pc
+ bic %1, %0, #0x3
+ orr %1, %1, #0x0c000001
+ teqp %1, #0 @ select FIQ mode
+ mov r0, r0
+ ldmia %2, {r8 - r14}
+ teqp %0, #0 @ return to SVC mode
+ mov r0, r0"
+#endif
+#ifdef CONFIG_CPU_32
+ "mrs %0, cpsr
+ bic %1, %0, #0xf
+ orr %1, %1, #0xc1
+ msr cpsr, %1 @ select FIQ mode
+ mov r0, r0
+ ldmia %2, {r8 - r14}
+ msr cpsr, %0 @ return to SVC mode
+ mov r0, r0"
#endif
+ : "=r" (tmp), "=r" (tmp2)
+ : "r" (®s->ARM_r8)
+ /* These registers aren't modified by the above code in a way
+ visible to the compiler, but we mark them as clobbers anyway
+ so that GCC won't put any of the input or output operands in
+ them. */
+ : "r8", "r9", "r10", "r11", "r12", "r13", "r14");
}
void get_fiq_regs(struct pt_regs *regs)
{
- /* not yet */
+ register unsigned long tmp, tmp2;
+ __asm__ volatile (
+#ifdef CONFIG_CPU_26
+ "mov %0, pc
+ bic %1, %0, #0x3
+ orr %1, %1, #0x0c000001
+ teqp %1, #0 @ select FIQ mode
+ mov r0, r0
+ stmia %2, {r8 - r14}
+ teqp %0, #0 @ return to SVC mode
+ mov r0, r0"
+#endif
+#ifdef CONFIG_CPU_32
+ "mrs %0, cpsr
+ bic %1, %0, #0xf
+ orr %1, %1, #0xc1
+ msr cpsr, %1 @ select FIQ mode
+ mov r0, r0
+ stmia %2, {r8 - r14}
+ msr cpsr, %0 @ return to SVC mode
+ mov r0, r0"
+#endif
+ : "=r" (tmp), "=r" (tmp2)
+ : "r" (®s->ARM_r8)
+ /* These registers aren't modified by the above code in a way
+ visible to the compiler, but we mark them as clobbers anyway
+ so that GCC won't put any of the input or output operands in
+ them. */
+ : "r8", "r9", "r10", "r11", "r12", "r13", "r14");
}
int claim_fiq(struct fiq_handler *f)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/head-armv.S linux.ac/arch/arm/kernel/head-armv.S
--- linux.vanilla/arch/arm/kernel/head-armv.S Tue Dec 22 23:19:26 1998
+++ linux.ac/arch/arm/kernel/head-armv.S Wed Feb 17 20:56:36 1999
@@ -8,12 +8,20 @@
#include
#include
-#ifndef CONFIG_ARCH_VNC
+#define DEBUG
+
+ .globl SYMBOL_NAME(swapper_pg_dir)
+ .equ SYMBOL_NAME(swapper_pg_dir), TEXTADDR - 0x4000
+
+ .section ".text.init",#alloc,#execinstr
+ENTRY(stext)
+ENTRY(_stext)
+
#if (TEXTADDR & 0xffff) != 0x8000
#error TEXTADDR must start at 0xXXXX8000
#endif
-#else
- .text
+
+#if defined(CONFIG_ARCH_VNC) || defined(CONFIG_ARCH_NETWINDER)
mov r0, r0
mov r0, r0
mov r0, r0
@@ -22,16 +30,34 @@
mov r0, r0
mov r0, r0
mov r0, r0
+
+ adr r2, 1f
+ ldmdb r2, {r7, r8}
+ and r3, r2, #0x0000c000
+ teq r3, #0x00008000
+ beq __entry
+ bic r3, r2, #0xc000
+ orr r3, r3, #0x8000
+ mov r0, r3
+ mov r4, #32
+ sub r5, r8, r7
+ b 1f
+
+ .word _stext
+ .word _end
+
+1: ldmia r2!, {r6, r7, r8, r9}
+ stmia r3!, {r6, r7, r8, r9}
+ subs r4, r4, #16
+ bcs 1b
+ movs r4, r5
+ mov r5, #0
+ movne pc, r0
+
mov r0, #0
mov r1, #5
#endif
-#define DEBUG
-
- .globl SYMBOL_NAME(swapper_pg_dir)
- .equ SYMBOL_NAME(swapper_pg_dir), TEXTADDR - 0x4000
-
- .text
/*
* Entry point and restart point. Entry *must* be called with r0 == 0,
* MMU off. Note! These should be unique!!! Please read Documentation/ARM-README
@@ -45,16 +71,15 @@
* r1 = 5 -> Corel Netwinder
* r1 = 6 -> CATS
* r1 = 7 -> tbox
+ * r1 = 8 -> SA110/21285 as co-processor
*/
-ENTRY(stext)
-ENTRY(_stext)
__entry: teq r0, #0 @ check for illegal entry...
bne .Lerror @ loop indefinitely
cmp r1, #8 @ Unknown machine architecture
bge .Lerror
-/* First thing to do is to get the page tables set up so that we can call the kernel
- * in the correct place. This is relocatable code...
+/* First thing to do is to get the page tables set up so that we can call
+ * the kernel in the correct place. This is relocatable code...
* - Read processor ID register (CP#15, CR0).
*/
mrc p15, 0, r9, c0, c0 @ get Processor ID
@@ -111,7 +136,11 @@
add r3, r3, #1 << 20
teq r0, r2
bne 1b
-#ifdef CONFIG_ARCH_VNC
+#ifdef CONFIG_ARCH_NETWINDER
+ teq r1, #5
+ bne 1f
+#endif
+#if defined(CONFIG_ARCH_VNC) || defined(CONFIG_ARCH_NETWINDER)
add r0, r4, #0x3f00
add r0, r0, #0x00f8
mov r3, #0x7c000000
@@ -120,6 +149,7 @@
add r3, r3, #1 << 20
str r3, [r0], #4
#endif
+1:
#endif
#ifdef CONFIG_ARCH_RPC
/* Map in screen at 0x02000000 & SCREEN2_BASE
@@ -250,7 +280,11 @@
mcr p15, 0, r4, c2, c0 @ load page table pointer
mov r0, #0x1f @ Domains 0, 1 = client
mcr p15, 0, r0, c3, c0 @ load domain access register
+#ifdef CONFIG_ALIGNMENT_TRAP
+ mov r0, #0x3f @ ....S..DPWCAM
+#else
mov r0, #0x3d @ ....S..DPWC.M
+#endif
orr r0, r0, #0x100
mov pc, lr
@@ -261,7 +295,11 @@
mcr p15, 0, r4, c2, c0 @ load page table pointer
mov r0, #0x1f @ Domains 0, 1 = client
mcr p15, 0, r0, c3, c0 @ load domain access register
+#ifdef CONFIG_ALIGNMENT_TRAP
+ mov r0, #0x7f @ ....S.LDPWCAM
+#else
mov r0, #0x7d @ ....S.LDPWC.M
+#endif
orr r0, r0, #0x100
mov pc, lr
@@ -276,12 +314,14 @@
mrc p15, 0, r0, c1, c0 @ get control register v4
bic r0, r0, #0x0e00
bic r0, r0, #0x0002
+#ifdef CONFIG_ALIGNMENT_TRAP
+ orr r0, r0, #0x003f @ I...S..DPWCAM
+#else
orr r0, r0, #0x003d @ I...S..DPWC.M
+#endif
orr r0, r0, #0x1100 @ v4 supports separate I cache
mov pc, lr
- .section ".text.init",#alloc,#execinstr
-
.Lsa_fastclock: mcr p15, 0, r4, c15, c1, 2 @ Enable clock switching
mov pc, lr
@@ -290,18 +330,22 @@
.long SYMBOL_NAME(__bss_start)
.long SYMBOL_NAME(processor_id)
.long SYMBOL_NAME(_end)
+ .long SYMBOL_NAME(cr_alignment)
.long SYMBOL_NAME(init_task_union)+8192
.align
.Lalready_done_mmap:
adr r4, .LC0
- ldmia r4, {r3, r4, r5, r6, r8, sp} @ Setup stack
+ ldmia r4, {r3, r4, r5, r6, r7, r8, sp} @ Setup stack
add r10, r10, r3 @ Add base back in
mov fp, #0
-1: cmp r5, r8 @ Clear BSS
+1: cmp r5, r7 @ Clear BSS
strcc fp, [r5],#4
bcc 1b
+ bic r2, r0, #2 @ Clear 'A' bit
+ stmia r8, {r0, r2} @ Save control register values
+
str r1, [r4] @ Save machine type
str r9, [r6] @ Save processor ID
mov lr, pc
@@ -362,7 +406,9 @@
beq 1001b
.endm
-#elif defined(CONFIG_ARCH_EBSA285)
+#elif defined(CONFIG_HOST_FOOTBRIDGE)
+#if 1
+/* For EBSA285 debugging */
.macro addruart,rx
mov \rx, #0xfe000000
.endm
@@ -379,26 +425,8 @@
.macro waituart,rd,rx
.endm
-
-#elif defined(CONFIG_ARCH_NEXUSPCI)
- .macro addruart,rx
- ldr \rx, =0xfff00000
- .endm
-
- .macro senduart,rd,rx
- str \rd, [\rx, #0xc]
- .endm
-
- .macro busyuart,rd,rx
-1001: ldr \rd, [\rx, #0x4]
- tst \rd, #1 << 0
- bne 1001b
- .endm
-
- .macro waituart,rd,rx
- .endm
-
-#elif defined(CONFIG_ARCH_VNC)
+#else
+/* For NetWinder debugging */
.macro addruart,rx
mov \rx, #0xff000000
orr \rx, \rx, #0x00e00000
@@ -421,6 +449,24 @@
tst \rd, #0x10
beq 1001b
.endm
+#endif
+#elif defined(CONFIG_ARCH_NEXUSPCI)
+ .macro addruart,rx
+ ldr \rx, =0xfff00000
+ .endm
+
+ .macro senduart,rd,rx
+ str \rd, [\rx, #0xc]
+ .endm
+
+ .macro busyuart,rd,rx
+1001: ldr \rd, [\rx, #0x4]
+ tst \rd, #1 << 0
+ bne 1001b
+ .endm
+
+ .macro waituart,rd,rx
+ .endm
#else
#error Unknown architecture
#endif
@@ -475,8 +521,6 @@
mov r1, r0
mov r0, #0
b 1b
-
- .ltorg
.bss
hexbuf: .space 16
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/hw-ebsa285.c linux.ac/arch/arm/kernel/hw-ebsa285.c
--- linux.vanilla/arch/arm/kernel/hw-ebsa285.c Mon Dec 28 23:09:40 1998
+++ linux.ac/arch/arm/kernel/hw-ebsa285.c Wed Jan 27 22:57:31 1999
@@ -3,27 +3,37 @@
*
* EBSA285 hardware specific functions
*
- * Copyright (C) 1998 Russell King, Phil Blundel
+ * Copyright (C) 1998 Russell King, Phil Blundell
*/
+#include
+#include
#include
#include
#include
#include
#include
#include
+#include
+#include
#include
+#include
+#include
#include
+#include
#include
-extern int setup_arm_irq(int, struct irqaction *);
+#define ETHER10_IO_BASE 0x301
+#define DEC21143_IO_BASE 0x401
+#define DEC21143_MEM_BASE 0x00800000
+#define CYBER2000_MEM_BASE 0x01000000
+extern int setup_arm_irq(int, struct irqaction *);
extern void pci_set_cmd(struct pci_dev *dev, unsigned short clear, unsigned short set);
extern void pci_set_base_addr(struct pci_dev *dev, int idx, unsigned int addr);
extern void pci_set_irq_line(struct pci_dev *dev, unsigned int irq);
-static int irqmap_ebsa[] __initdata = { 9, 8, 18, 11 };
-static int irqmap_cats[] __initdata = { 18, 8, 9, 11 };
+static int irqmap_ebsa[] __initdata = { IRQ_IN1, IRQ_IN0, IRQ_PCI, IRQ_IN3 };
__initfunc(static int ebsa_irqval(struct pci_dev *dev))
{
@@ -37,10 +47,13 @@
return irqmap_ebsa[(PCI_SLOT(dev->devfn) + pin) & 3];
}
+#ifdef CONFIG_CATS
+static int irqmap_cats[] __initdata = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 };
+
__initfunc(static int cats_irqval(struct pci_dev *dev))
{
if (dev->irq >= 128)
- return 32 + (dev->irq & 0x1f);
+ return 16 + (dev->irq & 0x1f);
switch (dev->irq) {
case 1:
@@ -56,77 +69,179 @@
dev->bus->number, dev->devfn, dev->irq);
return 0;
}
+#endif
__initfunc(void pcibios_fixup_ebsa285(struct pci_dev *dev))
{
- char cmd;
+ /* Latency timer of 32 */
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 32);
+ /* 32-byte cache line size */
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 8);
+ /* Set SysErr enable, Parity enable */
+ pci_set_cmd(dev, PCI_COMMAND_FAST_BACK, PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
/* sort out the irq mapping for this device */
switch (machine_type) {
case MACH_TYPE_EBSA285:
dev->irq = ebsa_irqval(dev);
+ /* Turn on bus mastering - boot loader doesn't
+ * - perhaps it should! - dag
+ */
+ pci_set_cmd(dev, 0, PCI_COMMAND_MASTER);
break;
+
+#ifdef CONFIG_CATS
case MACH_TYPE_CATS:
dev->irq = cats_irqval(dev);
+ /* Turn on bus mastering - boot loader doesn't
+ * - perhaps it should! - dag
+ */
+ pci_set_cmd(dev, 0, PCI_COMMAND_MASTER);
break;
+#endif
+#ifdef CONFIG_ARCH_NETWINDER
+ case MACH_TYPE_NETWINDER:
+ /* disable ROM */
+ pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0);
+
+#define DEV(v,d) ((v)<<16|(d))
+ switch (DEV(dev->vendor, dev->device)) {
+ /* Ether 100 */
+ case DEV(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142):
+ pci_set_base_addr(dev, 0, DEC21143_IO_BASE);
+ pci_set_base_addr(dev, 1, DEC21143_MEM_BASE);
+ pci_set_cmd(dev, 0, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
+ dev->irq = IRQ_NETWINDER_ETHER100;
+ break;
+
+ /* Ether 10 */
+ case DEV(PCI_VENDOR_ID_WINBOND2,0x5a5a):
+ pci_set_base_addr(dev, 0, ETHER10_IO_BASE);
+ pci_set_cmd(dev, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY, PCI_COMMAND_IO);
+ dev->irq = IRQ_NETWINDER_ETHER10;
+ break;
+
+ /* ISA bridge */
+ case DEV(PCI_VENDOR_ID_WINBOND,PCI_DEVICE_ID_WINBOND_83C553):
+ pci_set_base_addr(dev, 0, 0);
+ pci_set_cmd(dev, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY, PCI_COMMAND_IO);
+ /*
+ * Enable all memory requests from ISA to be channeled to PCI
+ */
+ pci_write_config_byte(dev, 0x48, 255);
+ /*
+ * Disable ping-pong (as per errata)
+ */
+ pci_write_config_byte(dev, 0x42, 0);
+ /*
+ * Enable PCI packet retry
+ */
+ pci_write_config_byte(dev, 0x40, 0x22);
+ /*
+ * Do not use PCI CPU park enable, park on
+ * last master, disable GAT bit
+ */
+ pci_write_config_byte(dev, 0x83, 0x02);
+ /*
+ * Default rotating priorities
+ */
+ pci_write_config_byte(dev, 0x80, 0xe0);
+ /*
+ * Rotate bank 4
+ */
+ pci_write_config_byte(dev, 0x81, 0x01);
+ break;
+
+ /* IDE */
+ case DEV(PCI_VENDOR_ID_WINBOND,PCI_DEVICE_ID_WINBOND_82C105):
+ pci_set_base_addr(dev, 0, 0x1f1);
+ pci_set_base_addr(dev, 1, 0x3f5);
+ pci_set_base_addr(dev, 2, 0x171);
+ pci_set_base_addr(dev, 3, 0x375);
+ pci_set_base_addr(dev, 4, 0xe801);
+ pci_set_cmd(dev, PCI_COMMAND_MEMORY, PCI_COMMAND_MASTER | PCI_COMMAND_IO);
+ dev->irq = IRQ_NETWINDER_IDE;
+ break;
+
+ /* VGA */
+ case DEV(PCI_VENDOR_ID_INTERG,0x2000):
+ pci_set_base_addr(dev, 0, CYBER2000_MEM_BASE);
+ pci_set_cmd(dev, PCI_COMMAND_MASTER, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+ dev->irq = IRQ_NETWINDER_VGA;
+ break;
+ }
+#endif
}
-
- /* Turn on bus mastering - boot loader doesn't
- * - perhaps it should! - dag
- */
- pci_read_config_byte(dev, PCI_COMMAND, &cmd);
- pci_write_config_byte(dev, PCI_COMMAND, cmd | PCI_COMMAND_MASTER);
}
-static void irq_pci_err(int irq, void *dev_id, struct pt_regs *regs)
+static void
+irq_pci_err(int irq, void *dev_id, struct pt_regs *regs)
{
- const char *err = "unknown";
- unsigned long cmd = *(unsigned long *)0xfe000004 & 0xffff;
- unsigned long ctrl = *(unsigned long *)0xfe00013c & 0xffffde07;
- static unsigned long next_warn[7];
- int idx = 6;
-
- switch(irq) {
- case IRQ_PCIPARITY:
- *(unsigned long *)0xfe000004 = cmd | 1 << 31;
- idx = 0;
- err = "parity";
- break;
+ static unsigned long next_warn;
+ unsigned long cmd = *CSR_PCICMD & 0x0000ffff;
+ unsigned long ctrl = (*CSR_SA110_CNTL) & 0xffffde07;
+ unsigned long irqstatus = *CSR_IRQ_RAWSTATUS;
+ struct pci_dev *dev;
+ int warn = time_after_eq(jiffies, next_warn);
+
+ if (warn) {
+ next_warn = jiffies + 3 * HZ / 100;
+ printk(KERN_DEBUG "PCI: ");
+ }
- case IRQ_PCITARGETABORT:
- *(unsigned long *)0xfe000004 = cmd | 1 << 28;
- idx = 1;
- err = "target abort";
- break;
+ if (irqstatus & (1 << 31)) {
+ if (warn)
+ printk("parity error ");
+ cmd |= 1 << 31;
+ }
- case IRQ_PCIMASTERABORT:
- *(unsigned long *)0xfe000004 = cmd | 1 << 29;
- idx = 2;
- err = "master abort";
- break;
+ if (irqstatus & (1 << 30)) {
+ if (warn)
+ printk("target abort ");
+ cmd |= 1 << 28;
+ }
- case IRQ_PCIDATAPARITY:
- *(unsigned long *)0xfe000004 = cmd | 1 << 24;
- idx = 3;
- err = "data parity";
- break;
+ if (irqstatus & (1 << 29)) {
+ if (warn)
+ printk("master abort ");
+ cmd |= 1 << 29;
+ }
- case IRQ_DISCARDTIMER:
- *(unsigned long *)0xfe00013c = ctrl | 1 << 8;
- idx = 4;
- err = "discard timer";
- break;
+ if (irqstatus & (1 << 28)) {
+ if (warn)
+ printk("data parity error ");
+ cmd |= 1 << 24;
+ }
- case IRQ_SERR:
- *(unsigned long *)0xfe00013c = ctrl | 1 << 3;
- idx = 5;
- err = "system";
- break;
+ if (irqstatus & (1 << 27)) {
+ if (warn)
+ printk("discard timer expired ");
+ ctrl |= SA110_CNTL_DISCARDTIMER;
}
- if (time_after_eq(jiffies, next_warn[idx])) {
- next_warn[idx] = jiffies + 3 * HZ / 100;
- printk(KERN_ERR "PCI %s error detected\n", err);
+
+ if (irqstatus & (1 << 23)) {
+ if (warn)
+ printk("system error ");
+ ctrl |= SA110_CNTL_RXSERR;
+ }
+
+ if (warn)
+ printk("pc=%08lX\n", instruction_pointer(regs));
+
+ for (dev = pci_devices; dev; dev = dev->next) {
+ unsigned short status;
+
+ pci_read_config_word(dev, PCI_STATUS, &status);
+ if (status & 0xf900) {
+ printk("PCI: [%04X:%04X] status = %X\n",
+ dev->vendor, dev->device, status);
+
+ pci_write_config_word(dev, PCI_STATUS, status & 0xf900);
+ }
}
+
+ *CSR_PCICMD = cmd;
+ *CSR_SA110_CNTL = ctrl;
}
static struct irqaction irq_pci_error = {
@@ -135,27 +250,384 @@
__initfunc(void pcibios_init_ebsa285(void))
{
- setup_arm_irq(IRQ_PCIPARITY, &irq_pci_error);
- setup_arm_irq(IRQ_PCITARGETABORT, &irq_pci_error);
- setup_arm_irq(IRQ_PCIMASTERABORT, &irq_pci_error);
- setup_arm_irq(IRQ_PCIDATAPARITY, &irq_pci_error);
- setup_arm_irq(IRQ_DISCARDTIMER, &irq_pci_error);
- setup_arm_irq(IRQ_SERR, &irq_pci_error);
+ unsigned int mem_size = (int)high_memory - PAGE_OFFSET;
+
+ setup_arm_irq(IRQ_PCI_ERR, &irq_pci_error);
/*
* Map our SDRAM at a known address in PCI space, just in case
- * the firmware had other ideas. Using a nonzero base is slightly
- * bizarre but apparently necessary to avoid problems with some
- * video cards.
- *
- * We should really only do this if the central function is enabled.
+ * the firmware had other ideas. Using a nonzero base is
+ * necessary, since some VGA cards forcefully use PCI addresses
+ * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards).
*/
- *(unsigned long *)0xfe000010 = 0;
- *(unsigned long *)0xfe000018 = 0xe0000000;
- *(unsigned long *)0xfe0000f8 = 0;
- *(unsigned long *)0xfe0000fc = 0;
- *(unsigned long *)0xfe000100 = 0x01fc0000;
- *(unsigned long *)0xfe000104 = 0;
- *(unsigned long *)0xfe000108 = 0x80000000;
- *(unsigned long *)0xfe000004 = 0x17;
+ *CSR_CSRBASEMASK = 0;
+ *CSR_CSRBASEOFFSET = 0;
+ *CSR_SDRAMBASEMASK = (mem_size - 1) & 0x0ffc0000;
+ *CSR_SDRAMBASEOFFSET = 0;
+ *CSR_ROMBASEMASK = 0x80000000;
+ *CSR_PCICACHELINESIZE = 0x00002008;
+ *CSR_PCICSRBASE = 0;
+ *CSR_PCICSRIOBASE = 0;
+ *CSR_PCISDRAMBASE = virt_to_bus((void *)PAGE_OFFSET);
+ *CSR_PCIROMBASE = 0;
+ *CSR_PCICMD = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+ PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY;
+ *CSR_PCIADDR_EXTN = 0;
+}
+
+/*
+ * Netwinder stuff
+ */
+#ifdef CONFIG_ARCH_NETWINDER
+/*
+ * This is a lock for accessing ports 0x338 and 0x33a
+ */
+spinlock_t __netwinder_data gpio_lock = SPIN_LOCK_UNLOCKED;
+
+static unsigned int __netwinder_data current_gpio_op = 0;
+static unsigned int __netwinder_data current_gpio_io = 0;
+static unsigned int __netwinder_data current_cpld = 0;
+
+void __netwinder_text gpio_modify_op(int mask, int set)
+{
+ unsigned int new_gpio, changed;
+unsigned long flags; save_flags_cli(flags);
+if ((flags & 128) == 0) {printk("gpio_modify_op called with IRQs enabled from %p\n", __builtin_return_address(0)); __backtrace(); }
+
+ new_gpio = (current_gpio_op & ~mask) | set;
+ changed = new_gpio ^ current_gpio_op;
+ current_gpio_op = new_gpio;
+
+ if (changed & 0xff)
+ outb(new_gpio, 0x338);
+ if (changed & 0xff00)
+ outb(new_gpio >> 8, 0x33a);
+restore_flags(flags);
+}
+
+static inline void __gpio_modify_io(int mask, int in)
+{
+ unsigned int new_gpio, changed;
+ int port;
+
+ new_gpio = (current_gpio_io & ~mask) | in;
+ changed = new_gpio ^ current_gpio_io;
+ current_gpio_io = new_gpio;
+
+ changed >>= 1;
+ new_gpio >>= 1;
+
+ outb(7, 0x370);
+ outb(7, 0x371);
+
+ for (port = 0xe1; changed && port < 0xe8; changed >>= 1) {
+ outb(port, 0x370);
+ outb(new_gpio & 1, 0x371);
+
+ port += 1;
+ new_gpio >>= 1;
+ }
+
+ outb(7, 0x370);
+ outb(8, 0x371);
+
+ for (port = 0xe8; changed && port < 0xec; changed >>= 1) {
+ outb(port, 0x370);
+ outb(new_gpio & 1, 0x371);
+
+ port += 1;
+ new_gpio >>= 1;
+ }
+}
+
+void __netwinder_text gpio_modify_io(int mask, int in)
+{
+ /* Open up the SuperIO chip */
+ outb(0x87, 0x370);
+ outb(0x87, 0x370);
+
+ __gpio_modify_io(mask, in);
+
+ /* Close up the EFER gate */
+ outb(0xaa, 0x370);
+}
+
+int __netwinder_text gpio_read(void)
+{
+ return inb(0x338) | inb(0x33a) << 8;
+}
+
+void __netwinder_text cpld_modify(int mask, int set)
+{
+ int msk;
+
+ current_cpld = (current_cpld & ~mask) | set;
+
+ gpio_modify_io(GPIO_DATA, 0);
+ gpio_modify_op(GPIO_IOLOAD, 0);
+
+ for (msk = 8; msk; msk >>= 1) {
+ int bit = current_cpld & msk;
+
+ gpio_modify_op(GPIO_DATA | GPIO_IOCLK, bit ? GPIO_DATA : 0);
+ gpio_modify_op(GPIO_IOCLK, GPIO_IOCLK);
+ }
+
+ gpio_modify_op(GPIO_IOCLK|GPIO_DATA, 0);
+ gpio_modify_op(GPIO_IOLOAD|GPIO_DSCLK, GPIO_IOLOAD|GPIO_DSCLK);
+ gpio_modify_op(GPIO_IOLOAD, 0);
+}
+
+__initfunc(static void hw_init_cpld(void))
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+ cpld_modify(-1, CPLD_UNMUTE | 4);
+ spin_unlock_irqrestore(&gpio_lock, flags);
}
+
+__initfunc(static void hw_init_wb553(void))
+{
+ unsigned long flags;
+#define WRITE_REG(r,v) do { outb((r), 0x370); outb((v), 0x371); } while (0)
+
+ /* Open up the SuperIO chip */
+ outb(0x87, 0x370);
+ outb(0x87, 0x370);
+
+ /* Set the serial interrupt numbers */
+ WRITE_REG(7, 5); /* keyboard subsection */
+ WRITE_REG(0x72, 5); /* interrupt number for mouse - IRQ5 */
+
+ WRITE_REG(7, 6); /* Infrared */
+ WRITE_REG(0x70, 6); /* IRQ 6 */
+
+ WRITE_REG(0x2a, 0xc1); /* Enable GP12, GP11, GP10 as I/O, CIRRX, IRRXH */
+
+ WRITE_REG(0x2b, 0x6b); /* Enable GP23, GP22, GP21, GP20, GP13 as I/O */
+
+ WRITE_REG(0x2c, 0x55); /* Enable GP17, GP16, GP15, GP14 as I/O */
+
+ current_gpio_io = -1;
+ __gpio_modify_io(-1, GPIO_DONE | GPIO_WDTIMER);
+
+ WRITE_REG(7, 7); /* Aux function group 1 (dev 7) */
+ WRITE_REG(0x60, 0x03); /* Group controlled by IO port 0x338 */
+ WRITE_REG(0x61, 0x38); /* GP 11, 12, 13, 14, 15, 16 */
+
+ WRITE_REG(0x70, 0x0a); /* IRQ10 for GP10 (Orange button) */
+
+ WRITE_REG(0xe0, 0x19); /* GP10 control reg set for debounce & input */
+ WRITE_REG(0x30, 0x01); /* Turn on section 7 (aux function group 1) */
+
+ WRITE_REG(7, 8); /* Aux function group 2 (dev 8) */
+ WRITE_REG(0x60, 0x03); /* Group controlled by IO port 0x33a */
+ WRITE_REG(0x61, 0x3a);
+
+ /* Clear watchdog timer regs */
+ WRITE_REG(0xf2, 0x00); /* Watchdog timeout value (disabled) */
+ WRITE_REG(0xf3, 0x00); /* Watchdog reg (reset to default) */
+ WRITE_REG(0xf4, 0x00); /* Reset if in timed out state (bit 0) */
+
+ /* T.B.D. set IRDA inputs (touch reg 2A, EC, ED) */
+ WRITE_REG(0x30, 0x01); /* Turn on section 8 (aux function group 2) */
+
+ spin_lock_irqsave(&gpio_lock, flags);
+ gpio_modify_op(-1, GPIO_RED_LED | GPIO_FAN);
+ spin_unlock_irqrestore(&gpio_loc, flags);
+
+ /* Close up the EFER gate */
+ outb(0xaa, 0x370);
+}
+
+static unsigned char rwa_unlock[] __initdata =
+{ 0x00, 0x00, 0x6a, 0xb5, 0xda, 0xed, 0xf6, 0xfb, 0x7d, 0xbe, 0xdf, 0x6f, 0x37, 0x1b,
+ 0x0d, 0x86, 0xc3, 0x61, 0xb0, 0x58, 0x2c, 0x16, 0x8b, 0x45, 0xa2, 0xd1, 0xe8, 0x74,
+ 0x3a, 0x9d, 0xce, 0xe7, 0x73, 0x39 };
+
+#ifndef DEBUG
+#define dprintk if (0) printk
+#else
+#define dprintk printk
+#endif
+
+__initfunc(static void hw_init_rwa010(void))
+{
+ unsigned char si[9];
+ int i, j;
+
+#define WRITE_RWA(r,v) do { outb((r), 0x279); outb((v), 0xa79); } while (0)
+
+ WRITE_RWA(2, 2);
+ mdelay(10);
+
+ for (i = 0; i < sizeof(rwa_unlock); i++)
+ outb(rwa_unlock[i], 0x279);
+
+ WRITE_RWA(3, 0);
+ WRITE_RWA(0, 128);
+
+ outb(1, 0x279);
+
+ mdelay(10);
+
+ dprintk("Identifier: ");
+ for (i = 0; i < 9; i++) {
+ si[i] = 0;
+ for (j = 0; j < 8; j++) {
+ int bit;
+ mdelay(1);
+ inb(0x203);
+ mdelay(1);
+ bit = inb(0x203);
+ dprintk("%02X ", bit);
+ si[i] |= bit << j;
+ }
+ mdelay(10);
+ dprintk("%02X ", si[i]);
+ }
+ dprintk("\n");
+
+ WRITE_RWA(6, 2); // Assign a card no = 2
+
+ dprintk("Card no = %d\n", inb(0x203));
+
+ WRITE_RWA(7, 3);
+ WRITE_RWA(0x30, 0);
+
+ WRITE_RWA(7, 4);
+ WRITE_RWA(0x30, 0);
+
+ WRITE_RWA(7, 2);
+ WRITE_RWA(0x30, 0);
+
+ WRITE_RWA(7, 5);
+
+ dprintk("Slider base: ");
+ WRITE_RWA(0x61, 1);
+ i = inb(0x203);
+
+ WRITE_RWA(0x60, 2);
+ dprintk("%02X%02X (201)\n", inb(0x203), i);
+
+ WRITE_RWA(0x30, 1);
+
+
+ WRITE_RWA(7, 0);
+
+ dprintk("WaveArtist base: ");
+ WRITE_RWA(0x61, 0x50);
+ i = inb(0x203);
+
+ WRITE_RWA(0x60, 0x02);
+ dprintk("%02X%02X (250),", inb(0x203), i);
+
+ WRITE_RWA(0x70, 3);
+ dprintk(" irq: %d (3),", inb(0x203));
+
+ WRITE_RWA(0x74, 7);
+ dprintk(" dma: %d (7)\n", inb(0x203));
+
+ WRITE_RWA(0x30, 1);
+
+ WRITE_RWA(7, 1);
+
+ dprintk("SoundBlaster base: ");
+ WRITE_RWA(0x61, 0x20);
+ i = inb(0x203);
+
+ WRITE_RWA(0x60, 0x02);
+ dprintk("%02X%02X (220),", inb(0x203), i);
+
+ dprintk(" irq: ");
+ WRITE_RWA(0x70, 3);
+ dprintk("%d (3),", inb(0x203));
+
+ dprintk(" 8-bit DMA: ");
+ WRITE_RWA(0x74, 1);
+ dprintk("%d (1)\n", inb(0x203));
+
+ dprintk("AdLib base: ");
+ WRITE_RWA(0x63, 0x88);
+ i = inb(0x203);
+
+ WRITE_RWA(0x62, 0x03);
+ dprintk("%02X%02X (388)\n", inb(0x203), i);
+
+ WRITE_RWA(0x30, 1);
+
+ outb(1, 0x226);
+ udelay(3);
+ outb(0, 0x226);
+
+ for (i = 0; i < 5; i++) {
+ if (inb(0x22e) & 0x80)
+ break;
+ mdelay(1);
+ }
+ if (i == 5)
+ printk("SoundBlaster: DSP reset failed\n");
+
+ dprintk("SoundBlaster DSP reset: %02X (AA)\n", inb(0x22a));
+
+ for (i = 0; i < 5; i++) {
+ if ((inb(0x22c) & 0x80) == 0)
+ break;
+ mdelay(1);
+ }
+
+ if (i == 5)
+ printk("SoundBlaster: DSP not ready\n");
+ else {
+ outb(0xe1, 0x22c);
+
+ dprintk("SoundBlaster DSP id: ");
+ i = inb(0x22a);
+ udelay(1);
+ i |= inb(0x22a) << 8;
+ dprintk("%04X\n", i);
+
+ for (i = 0; i < 5; i++) {
+ if ((inb(0x22c) & 0x80) == 0)
+ break;
+ mdelay(1);
+ }
+
+ if (i == 5)
+ printk("SoundBlaster: could not turn speaker off\n");
+
+ outb(0xd3, 0x22c);
+ }
+}
+
+__initfunc(void hw_init(void))
+{
+ unsigned long flags;
+
+ hw_init_wb553();
+ hw_init_cpld();
+ hw_init_rwa010();
+#if 0
+ /* does anyone want to have this in? */
+ drum();
+#endif
+
+#ifdef CONFIG_LEDS /* Clear both LEDs and start the LED driver up */
+ spin_lock_irqsave(&gpio_lock, flags);
+ gpio_modify_op(GPIO_RED_LED|GPIO_GREEN_LED, 0);
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ leds_event(led_start);
+#else /* Set the green LED on and the red LED off */
+ spin_lock_irqsave(&gpio_lock, flags);
+ gpio_modify_op(GPIO_RED_LED|GPIO_GREEN_LED, GPIO_GREEN_LED);
+ spin_unlock_irqrestore(&gpio_lock, flags);
+#endif /* CONFIG_LEDS */
+}
+
+EXPORT_SYMBOL(gpio_lock);
+EXPORT_SYMBOL(gpio_modify_op);
+EXPORT_SYMBOL(gpio_modify_io);
+EXPORT_SYMBOL(cpld_modify);
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/iic.c linux.ac/arch/arm/kernel/iic.c
--- linux.vanilla/arch/arm/kernel/iic.c Sun Nov 8 15:08:43 1998
+++ linux.ac/arch/arm/kernel/iic.c Sat Jan 9 16:40:25 1999
@@ -9,8 +9,11 @@
#include
#include
-#include
#include
+#include
+#include
+
+#define FORCE_ONES 0xdc
/*
* if delay loop has been calibrated then us that,
@@ -42,7 +45,7 @@
{
unsigned char out;
- out = inb(IOC_CONTROL) | 0xc2;
+ out = inb(IOC_CONTROL) | FORCE_ONES | 0x02;
outb(out, IOC_CONTROL);
iic_delay();
@@ -55,7 +58,7 @@
{
unsigned char out;
- out = inb(IOC_CONTROL) | 0xc3;
+ out = inb(IOC_CONTROL) | FORCE_ONES | 0x03;
iic_delay();
outb(out ^ 1, IOC_CONTROL);
@@ -69,7 +72,7 @@
unsigned char out, in;
int i;
- out = (inb(IOC_CONTROL) & 0xfc) | 0xc0;
+ out = (inb(IOC_CONTROL) & 0xfc) | FORCE_ONES;
outb(out, IOC_CONTROL);
for (i = 7; i >= 0; i--) {
@@ -110,7 +113,7 @@
unsigned char out, in;
int i;
- out = (inb(IOC_CONTROL) & 0xfc) | 0xc0;
+ out = (inb(IOC_CONTROL) & 0xfc) | FORCE_ONES;
outb(out, IOC_CONTROL);
in = 0;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/init_task.c linux.ac/arch/arm/kernel/init_task.c
--- linux.vanilla/arch/arm/kernel/init_task.c Tue Dec 22 23:19:26 1998
+++ linux.ac/arch/arm/kernel/init_task.c Mon Dec 28 10:05:48 1998
@@ -6,6 +6,7 @@
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
+static struct file * init_fd_array[NR_OPEN] = { NULL, };
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
struct mm_struct init_mm = INIT_MM;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/ioport.c linux.ac/arch/arm/kernel/ioport.c
--- linux.vanilla/arch/arm/kernel/ioport.c Sun Nov 8 15:08:43 1998
+++ linux.ac/arch/arm/kernel/ioport.c Thu Jan 1 01:00:00 1970
@@ -1,29 +0,0 @@
-/*
- * linux/arch/arm/kernel/ioport.c
- *
- * Io-port support is not used for ARM
- */
-
-#include
-#include
-#include
-#include
-#include
-
-/* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */
-/*asmlinkage void set_bitmap(unsigned long *bitmap, short base, short extent, int new_value)
-{
-}*/
-
-asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
-{
- return -ENOSYS;
-}
-
-asmlinkage int sys_iopl(long ebx,long ecx,long edx,
- long esi, long edi, long ebp, long eax, long ds,
- long es, long fs, long gs, long orig_eax,
- long eip,long cs,long eflags,long esp,long ss)
-{
- return -ENOSYS;
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/irq.c linux.ac/arch/arm/kernel/irq.c
--- linux.vanilla/arch/arm/kernel/irq.c Mon Dec 28 23:09:40 1998
+++ linux.ac/arch/arm/kernel/irq.c Wed Feb 17 20:56:22 1999
@@ -49,6 +49,7 @@
unsigned int local_bh_count[NR_CPUS];
unsigned int local_irq_count[NR_CPUS];
spinlock_t irq_controller_lock;
+int setup_arm_irq(int, struct irqaction *);
extern int get_fiq_list(char *);
extern void init_FIQ(void);
@@ -60,7 +61,8 @@
unsigned int probing : 1; /* IRQ in use for a probe */
unsigned int probe_ok : 1; /* IRQ can be used for probe */
unsigned int valid : 1; /* IRQ claimable */
- unsigned int unused :26;
+ unsigned int noautoenable : 1; /* don't automatically enable IRQ */
+ unsigned int unused :25;
void (*mask_ack)(unsigned int irq); /* Mask and acknowledge IRQ */
void (*mask)(unsigned int irq); /* Mask IRQ */
void (*unmask)(unsigned int irq); /* Unmask IRQ */
@@ -71,6 +73,12 @@
static struct irqdesc irq_desc[NR_IRQS];
/*
+ * Get architecture specific interrupt handlers
+ * and interrupt initialisation.
+ */
+#include
+
+/*
* Dummy mask/unmask handler
*/
static void dummy_mask_unmask_irq(unsigned int irq)
@@ -94,10 +102,12 @@
spin_lock_irqsave(&irq_controller_lock, flags);
cliIF();
- irq_desc[irq].enabled = 1;
irq_desc[irq].probing = 0;
irq_desc[irq].triggered = 0;
- irq_desc[irq].unmask(irq);
+ if (!irq_desc[irq].noautoenable) {
+ irq_desc[irq].enabled = 1;
+ irq_desc[irq].unmask(irq);
+ }
spin_unlock_irqrestore(&irq_controller_lock, flags);
}
@@ -119,7 +129,7 @@
*p++ = '\n';
}
-#ifdef CONFIG_ACORN
+#ifdef CONFIG_ARCH_ACORN
p += get_fiq_list(p);
#endif
return p - buf;
@@ -130,10 +140,14 @@
*/
asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
{
- struct irqdesc * desc = irq_desc + irq;
+ struct irqdesc * desc;
struct irqaction * action;
int status, cpu;
+ irq = fixup_irq(irq);
+
+ desc = irq_desc + irq;
+
spin_lock(&irq_controller_lock);
desc->mask_ack(irq);
spin_unlock(&irq_controller_lock);
@@ -252,19 +266,17 @@
if (!shared) {
irq_desc[irq].nomask = (new->flags & SA_IRQNOMASK) ? 1 : 0;
- irq_desc[irq].enabled = 1;
irq_desc[irq].probing = 0;
- irq_desc[irq].unmask(irq);
+ if (!irq_desc[irq].noautoenable) {
+ irq_desc[irq].enabled = 1;
+ irq_desc[irq].unmask(irq);
+ }
}
spin_unlock_irqrestore(&irq_controller_lock, flags);
return 0;
}
-/*
- * Using "struct sigaction" is slightly silly, but there
- * are historical reasons and it works well, so..
- */
int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
unsigned long irq_flags, const char * devname, void *dev_id)
{
@@ -346,7 +358,6 @@
continue;
irq_desc[i].probing = 1;
- irq_desc[i].enabled = 1;
irq_desc[i].triggered = 0;
irq_desc[i].unmask(i);
irqs += 1;
@@ -364,7 +375,8 @@
*/
spin_lock_irq(&irq_controller_lock);
for (i = 0; i < NR_IRQS; i++) {
- if (irq_desc[i].probing && irq_desc[i].triggered) {
+ if (irq_desc[i].probing &&
+ irq_desc[i].triggered) {
irq_desc[i].probing = 0;
irqs -= 1;
}
@@ -383,7 +395,7 @@
int probe_irq_off(unsigned long irqs)
{
unsigned int i;
- int irq_found = -1;
+ int irq_found = NO_IRQ;
/*
* look at the interrupts, and find exactly one
@@ -393,7 +405,7 @@
for (i = 0; i < NR_IRQS; i++) {
if (irq_desc[i].probing &&
irq_desc[i].triggered) {
- if (irq_found != -1) {
+ if (irq_found != NO_IRQ) {
irq_found = NO_IRQ;
goto out;
}
@@ -405,21 +417,19 @@
irq_found = NO_IRQ;
out:
spin_unlock_irq(&irq_controller_lock);
+
return irq_found;
}
-/*
- * Get architecture specific interrupt handlers
- * and interrupt initialisation.
- */
-#include
-
__initfunc(void init_IRQ(void))
{
extern void init_dma(void);
int irq;
for (irq = 0; irq < NR_IRQS; irq++) {
+ irq_desc[irq].probe_ok = 0;
+ irq_desc[irq].valid = 0;
+ irq_desc[irq].noautoenable = 0;
irq_desc[irq].mask_ack = dummy_mask_unmask_irq;
irq_desc[irq].mask = dummy_mask_unmask_irq;
irq_desc[irq].unmask = dummy_mask_unmask_irq;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/leds-ebsa285.c linux.ac/arch/arm/kernel/leds-ebsa285.c
--- linux.vanilla/arch/arm/kernel/leds-ebsa285.c Sun Nov 8 15:08:44 1998
+++ linux.ac/arch/arm/kernel/leds-ebsa285.c Sat Jan 23 23:35:01 1999
@@ -9,36 +9,77 @@
* - Amber - On if system is not idle
* - Red - currently unused
*/
+#include
+#include
+#include
+
#include
#include
+#include
#include
-static char led_state = XBUS_LED_RED | XBUS_LED_GREEN;
+static int led_state;
+static char ebsa_led_state = XBUS_LED_RED | XBUS_LED_GREEN;
void leds_event(led_event_t ledevt)
{
unsigned long flags;
+ switch (ledevt) {
+ case led_start:
+ led_state = !machine_is_cats();
+ return;
+
+ case led_stop:
+ led_state = 0;
+ return;
+
+ default:
+ break;
+ }
+
+ if (!led_state)
+ return;
+
save_flags_cli(flags);
switch(ledevt) {
+#ifdef CONFIG_LEDS_CPU
case led_idle_start:
- led_state |= XBUS_LED_AMBER;
+ ebsa_led_state |= XBUS_LED_AMBER;
break;
case led_idle_end:
- led_state &= ~XBUS_LED_AMBER;
+ ebsa_led_state &= ~XBUS_LED_AMBER;
break;
-
+#endif
+#ifdef CONFIG_LEDS_TIMER
case led_timer:
- led_state ^= XBUS_LED_GREEN;
+ ebsa_led_state ^= XBUS_LED_GREEN;
break;
-
+#endif
default:
break;
}
restore_flags(flags);
- *XBUS_LEDS = led_state;
+ switch (machine_type) {
+#ifdef CONFIG_ARCH_EBSA285
+ case MACH_TYPE_EBSA285:
+ *XBUS_LEDS = led_state;
+ break;
+#endif
+#ifdef CONFIG_ARCH_NETWINDER
+ case MACH_TYPE_NETWINDER:
+ spin_lock_irqsave(&gpio_lock, flags);
+ gpio_modify_op(GPIO_RED_LED | GPIO_GREEN_LED,
+ (ebsa_led_state & XBUS_LED_AMBER ? GPIO_RED_LED : 0) |
+ (ebsa_led_state & XBUS_LED_GREEN ? GPIO_GREEN_LED : 0));
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ break;
+#endif
+ default:
+ break;
+ }
}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/oldlatches.c linux.ac/arch/arm/kernel/oldlatches.c
--- linux.vanilla/arch/arm/kernel/oldlatches.c Sun Nov 8 15:08:43 1998
+++ linux.ac/arch/arm/kernel/oldlatches.c Mon Feb 22 21:52:36 1999
@@ -4,6 +4,7 @@
* (c) David Alan Gilbert 1995/1996
*/
#include
+#include
#include
#include
@@ -40,7 +41,7 @@
}
#endif
-void oldlatch_init(void)
+void __init oldlatch_init(void)
{
printk("oldlatch: init\n");
#ifdef LATCHAADDR
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/process.c linux.ac/arch/arm/kernel/process.c
--- linux.vanilla/arch/arm/kernel/process.c Sun Nov 8 15:08:44 1998
+++ linux.ac/arch/arm/kernel/process.c Fri Jan 22 23:00:37 1999
@@ -55,46 +55,37 @@
}
/*
- * The idle loop on an arm..
+ * The idle loop on an ARM...
*/
asmlinkage int sys_idle(void)
{
- int ret = -EPERM;
-
- lock_kernel();
if (current->pid != 0)
- goto out;
+ return -EPERM;
+
/* endless idle loop with no priority at all */
- current->priority = -100;
- for (;;)
- {
+ while (1) {
+ if (!current->need_resched && !hlt_counter)
+ proc_idle();
+ current->policy = SCHED_YIELD;
+ schedule();
+#ifndef CONFIG_NO_PGT_CACHE
check_pgt_cache();
-#if 0 //def ARCH_IDLE_OK
- if (!hlt_counter && !current->need_resched)
- proc_idle ();
#endif
- run_task_queue(&tq_scheduler);
- schedule();
}
- ret = 0;
-out:
- unlock_kernel();
- return ret;
}
+static char reboot_mode = 'h';
+
__initfunc(void reboot_setup(char *str, int *ints))
{
+ reboot_mode = str[0];
}
-/*
- * This routine reboots the machine by resetting the expansion cards via
- * their loaders, turning off the processor cache (if ARM3), copying the
- * first instruction of the ROM to 0, and executing it there.
- */
void machine_restart(char * __unused)
{
- proc_hard_reset ();
- arch_hard_reset ();
+ arch_reset(reboot_mode);
+ panic("Reboot failed\n");
+ while (1);
}
void machine_halt(void)
@@ -150,6 +141,67 @@
}
/*
+ * Task structure and kernel stack allocation.
+ *
+ * Taken from the i386 version.
+ */
+#ifdef CONFIG_CPU_32
+#define EXTRA_TASK_STRUCT 8
+static struct task_struct *task_struct_stack[EXTRA_TASK_STRUCT];
+static int task_struct_stack_ptr = -1;
+#endif
+
+struct task_struct *alloc_task_struct(void)
+{
+ struct task_struct *tsk;
+
+#ifndef EXTRA_TASK_STRUCT
+ tsk = ll_alloc_task_struct();
+#else
+ int index;
+
+ index = task_struct_stack_ptr;
+ if (index >= EXTRA_TASK_STRUCT/2)
+ goto use_cache;
+
+ tsk = ll_alloc_task_struct();
+
+ if (!tsk) {
+ index = task_struct_stack_ptr;
+
+ if (index >= 0) {
+use_cache: tsk = task_struct_stack[index];
+ task_struct_stack_ptr = index - 1;
+ }
+ }
+#endif
+#ifdef CONFIG_SYSRQ
+ /* You need this if you want SYSRQ-T to give sensible stack
+ * usage information
+ */
+ if (tsk) {
+ char *p = (char *)tsk;
+ memzero(p+KERNEL_STACK_SIZE, KERNEL_STACK_SIZE);
+ }
+#endif
+
+ return tsk;
+}
+
+void free_task_struct(struct task_struct *p)
+{
+#ifdef EXTRA_TASK_STRUCT
+ int index = task_struct_stack_ptr + 1;
+
+ if (index < EXTRA_TASK_STRUCT) {
+ task_struct_stack[index] = p;
+ task_struct_stack_ptr = index;
+ } else
+#endif
+ ll_free_task_struct(p);
+}
+
+/*
* Free current thread data structures etc..
*/
void exit_thread(void)
@@ -179,9 +231,10 @@
childregs = ((struct pt_regs *)((unsigned long)p + 8192)) - 1;
*childregs = *regs;
childregs->ARM_r0 = 0;
+ childregs->ARM_sp = esp;
save = ((struct context_save_struct *)(childregs)) - 1;
- copy_thread_css(save);
+ init_thread_css(save);
p->tss.save = save;
return 0;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/setup.c linux.ac/arch/arm/kernel/setup.c
--- linux.vanilla/arch/arm/kernel/setup.c Tue Dec 22 23:19:27 1998
+++ linux.ac/arch/arm/kernel/setup.c Sun Feb 28 09:21:05 1999
@@ -56,12 +56,16 @@
#define SUPPORT_CPU_SA110
#endif
-#ifndef CONFIG_CMDLINE
-#define CONFIG_CMDLINE "root=/dev/nfs rw"
-#endif
#define MEM_SIZE (16*1024*1024)
#define COMMAND_LINE_SIZE 256
+#ifndef CONFIG_CMDLINE
+#define CONFIG_CMDLINE ""
+#endif
+
+extern void reboot_setup(char *str, int *ints);
+extern void disable_hlt(void);
+
struct drive_info_struct { char dummy[32]; } drive_info;
struct screen_info screen_info = {
orig_video_lines: 30,
@@ -87,20 +91,26 @@
/*-- Match -- --- Mask -- -- Manu -- Processor uname -m --- ELF STUFF ---
--- processor asm funcs --- */
#if defined(CONFIG_CPU_26)
+ /* ARM2 fake ident */
{ 0x41560200, 0xfffffff0, "ARM/VLSI", "arm2" , "armv1" , "v1", 0,
&arm2_processor_functions },
+ /* ARM250 fake ident */
{ 0x41560250, 0xfffffff0, "ARM/VLSI", "arm250" , "armv2" , "v2", HWCAP_SWP,
&arm250_processor_functions },
+ /* ARM3 processors */
{ 0x41560300, 0xfffffff0, "ARM/VLSI", "arm3" , "armv2" , "v2", HWCAP_SWP,
&arm3_processor_functions },
#elif defined(CONFIG_CPU_32)
#ifdef SUPPORT_CPU_ARM6
+ /* ARM6 */
{ 0x41560600, 0xfffffff0, "ARM/VLSI", "arm6" , "armv3" , "v3", HWCAP_SWP,
&arm6_processor_functions },
+ /* ARM610 */
{ 0x41560610, 0xfffffff0, "ARM/VLSI", "arm610" , "armv3" , "v3", HWCAP_SWP,
&arm6_processor_functions },
#endif
#ifdef SUPPORT_CPU_ARM7
+ /* ARM7's have a strange numbering */
{ 0x41007000, 0xffffff00, "ARM/VLSI", "arm7" , "armv3" , "v3", HWCAP_SWP,
&arm7_processor_functions },
/* ARM710 IDs are non-standard */
@@ -108,10 +118,16 @@
&arm7_processor_functions },
#endif
#ifdef SUPPORT_CPU_SA110
- { 0x4401a100, 0xfffffff0, "DEC", "sa110" , "armv4" , "v3", HWCAP_SWP|HWCAP_HALF,
+#ifdef CONFIG_ARCH_RPC
+ /* Acorn RiscPC's can't handle ARMv4 half-word instructions */
+ { 0x4401a100, 0xfffffff0, "Intel", "sa110" , "armv4" , "v4", HWCAP_SWP,
+ &sa110_processor_functions },
+#else
+ { 0x4401a100, 0xfffffff0, "Intel", "sa110" , "armv4" , "v4", HWCAP_SWP|HWCAP_HALF,
&sa110_processor_functions },
#endif
#endif
+#endif
{ 0x00000000, 0x00000000, "***", "unknown", "unknown", "**", 0, NULL }
};
@@ -132,139 +148,10 @@
*/
/*
- * Risc-PC specific initialisation
- */
-#ifdef CONFIG_ARCH_RPC
-
-#include
-
-unsigned int vram_half_sam;
-
-static void
-setup_rpc(struct param_struct *params)
-{
- extern void init_dram_banks(const struct param_struct *params);
-
- init_dram_banks(params);
-
- switch (params->u1.s.pages_in_vram) {
- case 256:
- vram_half_sam = 1024;
- break;
- case 512:
- default:
- vram_half_sam = 2048;
- }
-}
-#else
-#define setup_rpc(x)
-#endif
-
-#ifdef PARAMS_BASE
-
-#ifdef CONFIG_ARCH_ACORN
-int memc_ctrl_reg;
-int number_ide_drives;
-int number_mfm_drives;
-#endif
-
-static struct param_struct *params = (struct param_struct *)PARAMS_BASE;
-
-__initfunc(static char *
-setup_params(unsigned long *mem_end_p))
-{
- ROOT_DEV = to_kdev_t(params->u1.s.rootdev);
- ORIG_X = params->u1.s.video_x;
- ORIG_Y = params->u1.s.video_y;
- ORIG_VIDEO_COLS = params->u1.s.video_num_cols;
- ORIG_VIDEO_LINES = params->u1.s.video_num_rows;
-
-#ifdef CONFIG_ARCH_ACORN
-#ifndef CONFIG_FB
- {
- extern int bytes_per_char_h;
- extern int bytes_per_char_v;
-
- bytes_per_char_h = params->u1.s.bytes_per_char_h;
- bytes_per_char_v = params->u1.s.bytes_per_char_v;
- }
-#endif
- memc_ctrl_reg = params->u1.s.memc_control_reg;
- number_ide_drives = (params->u1.s.adfsdrives >> 6) & 3;
- number_mfm_drives = (params->u1.s.adfsdrives >> 3) & 3;
-
- setup_rpc(params);
-
- if (!(params->u1.s.flags & FLAG_READONLY))
- root_mountflags &= ~MS_RDONLY;
-#endif
-#ifdef CONFIG_BLK_DEV_RAM
- {
- extern int rd_doload;
- extern int rd_prompt;
- extern int rd_image_start;
-
- rd_image_start = params->u1.s.rd_start;
- rd_prompt = (params->u1.s.flags & FLAG_RDPROMPT) == 0;
- rd_doload = (params->u1.s.flags & FLAG_RDLOAD) == 0;
- }
-#endif
-
-#ifdef CONFIG_ARCH_ACORN
- *mem_end_p = GET_MEMORY_END(params);
-#elif defined(CONFIG_ARCH_EBSA285)
- *mem_end_p = PAGE_OFFSET + params->u1.s.page_size * params->u1.s.nr_pages;
-#else
- *mem_end_p = PAGE_OFFSET + MEM_SIZE;
-#endif
-
- return params->commandline;
-}
-
-#else
-
-static char default_command_line[] __initdata = CONFIG_CMDLINE;
-
-__initfunc(static char *
-setup_params(unsigned long *mem_end_p))
-{
- ROOT_DEV = 0x00ff;
-
-#ifdef CONFIG_BLK_DEV_RAM
- {
- extern int rd_doload;
- extern int rd_prompt;
- extern int rd_image_start;
-
- rd_image_start = 0;
- rd_prompt = 1;
- rd_doload = 1;
- }
-#endif
-
- *mem_end_p = PAGE_OFFSET + MEM_SIZE;
-
- return default_command_line;
-}
-#endif
-
-/*
* initial ram disk
*/
#ifdef CONFIG_BLK_DEV_INITRD
__initfunc(static void
-setup_initrd(const struct param_struct *params))
-{
- if (params->u1.s.initrd_start) {
- initrd_start = params->u1.s.initrd_start;
- initrd_end = initrd_start + params->u1.s.initrd_size;
- } else {
- initrd_start = 0;
- initrd_end = 0;
- }
-}
-
-__initfunc(static void
check_initrd(unsigned long mem_start, unsigned long mem_end))
{
if (initrd_end > mem_end) {
@@ -276,7 +163,6 @@
}
#else
-#define setup_initrd(p)
#define check_initrd(ms,me)
#endif
@@ -289,48 +175,47 @@
armidlist[armidindex].mask)
armidindex += 1;
- if (armidlist[armidindex].id == 0) {
-#ifdef CONFIG_ARCH_ACORN
- int i;
-
- for (i = 0; i < 3200; i++)
- ((unsigned long *)SCREEN2_BASE)[i] = 0x77113322;
-#endif
+ if (armidlist[armidindex].id == 0)
while (1);
- }
processor = *armidlist[armidindex].proc;
processor._proc_init();
}
+static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
static char command_line[COMMAND_LINE_SIZE] = { 0, };
char saved_command_line[COMMAND_LINE_SIZE];
__initfunc(static void
-setup_mem(char *cmd_line, unsigned long *mem_start, unsigned long *mem_end))
+setup_mem(char *cmd_line, unsigned long *mem_start, unsigned long *mem_sz))
{
- char c, *to = command_line;
+ char c = ' ', *to = command_line;
int len = 0;
*mem_start = (unsigned long)&_end;
for (;;) {
- if (cmd_line[0] == ' ' &&
- cmd_line[1] == 'm' &&
- cmd_line[2] == 'e' &&
- cmd_line[3] == 'm' &&
- cmd_line[4] == '=') {
- *mem_end = simple_strtoul(cmd_line+5, &cmd_line, 0);
- switch(*cmd_line) {
- case 'M':
- case 'm':
- *mem_end <<= 10;
- case 'K':
- case 'k':
- *mem_end <<= 10;
+ if (c == ' ') {
+ if (cmd_line[0] == 'm' &&
+ cmd_line[1] == 'e' &&
+ cmd_line[2] == 'm' &&
+ cmd_line[3] == '=') {
+ *mem_sz = simple_strtoul(cmd_line+4, &cmd_line, 0);
+ switch(*cmd_line) {
+ case 'M':
+ case 'm':
+ *mem_sz <<= 10;
+ case 'K':
+ case 'k':
+ *mem_sz <<= 10;
+ cmd_line++;
+ }
+ }
+ /* if there are two spaces, remove one */
+ if (*cmd_line == ' ') {
cmd_line++;
+ continue;
}
- *mem_end = *mem_end + PAGE_OFFSET;
}
c = *cmd_line++;
if (!c)
@@ -341,8 +226,50 @@
}
*to = '\0';
+
+ /* remove trailing spaces */
+ while (*--to == ' ' && to != command_line)
+ *to = '\0';
+}
+
+__initfunc(static void
+setup_ram(int doload, int prompt, int image_start))
+{
+#ifdef CONFIG_BLK_DEV_RAM
+ extern int rd_doload;
+ extern int rd_prompt;
+ extern int rd_image_start;
+
+ rd_image_start = image_start;
+ rd_prompt = prompt;
+ rd_doload = doload;
+#endif
}
+/*
+ * initial ram disk
+ */
+__initfunc(static void
+setup_initrd(unsigned int start, unsigned int size))
+{
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (start) {
+ initrd_start = start;
+ initrd_end = start + size;
+ } else {
+ initrd_start = 0;
+ initrd_end = 0;
+ }
+#endif
+}
+
+#ifdef CONFIG_ARCH_ACORN
+int memc_ctrl_reg;
+int number_mfm_drives;
+unsigned int vram_size;
+int acornfb_depth;
+#endif
+
__initfunc(void
setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p))
{
@@ -350,6 +277,11 @@
unsigned long memory_end;
char endian = 'l';
char *from;
+#ifdef PARAMS_BASE
+ struct param_struct *params = (struct param_struct *)PARAMS_BASE;
+#else
+ struct param_struct *params = NULL;
+#endif
if (smptrap == 1)
return;
@@ -357,23 +289,153 @@
setup_processor();
- from = setup_params(&memory_end);
- setup_initrd(params);
+ init_task.mm->start_code = TASK_SIZE;
+ init_task.mm->end_code = TASK_SIZE + (unsigned long) &_etext;
+ init_task.mm->end_data = TASK_SIZE + (unsigned long) &_edata;
+ init_task.mm->brk = TASK_SIZE + (unsigned long) &_end;
+
+ /*
+ * Add your machine dependencies here
+ */
+#ifndef CONFIG_CPU_26
+ switch (machine_type) {
+ case MACH_TYPE_EBSA110:
+ /* EBSA110 locks if we execute 'wait for interrupt' */
+ disable_hlt();
+ params = NULL;
+ break;
+
+ case MACH_TYPE_CATS:
+ /* CATS must use soft-reboot */
+ reboot_setup("s", NULL);
+ break;
+
+ case MACH_TYPE_NETWINDER:
+ /*
+ * to be fixed in a future NeTTrom
+ */
+ if (params->u1.s.page_size == 4096) {
+ if (params->u1.s.nr_pages != 0x2000 &&
+ params->u1.s.nr_pages != 0x4000) {
+ printk("Warning: bad NeTTrom parameters detected, using defaults\n");
+ /*
+ * This stuff doesn't appear to be initialised
+ * properly by NeTTrom 2.0.6 and 2.0.7
+ */
+ params->u1.s.nr_pages = 0x2000; /* 32MB */
+ params->u1.s.ramdisk_size = 0;
+ params->u1.s.flags = FLAG_READONLY;
+ params->u1.s.initrd_start = 0;
+ params->u1.s.initrd_size = 0;
+ params->u1.s.rd_start = 0;
+ params->u1.s.video_x = 0;
+ params->u1.s.video_y = 0;
+ params->u1.s.video_num_cols = 80;
+ params->u1.s.video_num_rows = 30;
+ }
+ } else {
+ printk("Warning: no NeTTrom parameter page detected, using "
+ "compiled-in settings\n");
+ params = NULL;
+ }
+ break;
+
+ default:
+ break;
+ }
+#endif
+
+ if (params) {
+ memory_end = params->u1.s.page_size *
+ params->u1.s.nr_pages;
+
+ ROOT_DEV = to_kdev_t(params->u1.s.rootdev);
+#ifdef CONFIG_OLD_CONSOLE
+ ORIG_X = params->u1.s.video_x;
+ ORIG_Y = params->u1.s.video_y;
+ ORIG_VIDEO_COLS = params->u1.s.video_num_cols;
+ ORIG_VIDEO_LINES = params->u1.s.video_num_rows;
+#endif
+
+ setup_ram((params->u1.s.flags & FLAG_RDLOAD) == 0,
+ (params->u1.s.flags & FLAG_RDPROMPT) == 0,
+ params->u1.s.rd_start);
+
+ setup_initrd(params->u1.s.initrd_start,
+ params->u1.s.initrd_size);
+
+ if (!(params->u1.s.flags & FLAG_READONLY))
+ root_mountflags &= ~MS_RDONLY;
+
+#ifdef CONFIG_ARCH_ACORN
+ memc_ctrl_reg = params->u1.s.memc_control_reg;
+ number_mfm_drives = (params->u1.s.adfsdrives >> 3) & 3;
+#ifdef CONFIG_OLD_CONSOLE
+ {
+ extern int bytes_per_char_h;
+ extern int bytes_per_char_v;
+
+ bytes_per_char_h = params->u1.s.bytes_per_char_h;
+ bytes_per_char_v = params->u1.s.bytes_per_char_v;
+ }
+#elif defined(CONFIG_FB_ACORN)
+ {
+ switch (params->u1.s.bytes_per_char_h) {
+ case 1: acornfb_depth = 1; break;
+ case 2: acornfb_depth = 2; break;
+ case 4: acornfb_depth = 4; break;
+ case 8: acornfb_depth = 8; break;
+ case 24: acornfb_depth = 24; break;
+ default: acornfb_depth = 8; break;
+ }
+ }
+#endif
+
+#ifdef CONFIG_ARCH_RPC
+ {
+ extern void init_dram_banks(struct param_struct *);
+ init_dram_banks(params);
+ }
+#endif
+
+ vram_size = 0;
+
+ switch (params->u1.s.pages_in_vram) {
+ case 512:
+ vram_size += PAGE_SIZE * 256;
+ case 256:
+ vram_size += PAGE_SIZE * 256;
+ default:
+ break;
+ }
+
+ memory_end -= vram_size;
+#endif
+
+ from = params->commandline;
+ } else {
+ memory_end = MEM_SIZE;
+ ROOT_DEV = 0x00ff;
+
+ setup_ram(1, 1, 0);
+ setup_initrd(0, 0);
+
+ from = default_command_line;
+ }
+
+#ifdef CONFIG_NWFPE
+ fpe_init();
+#endif
/* Save unparsed command line copy for /proc/cmdline */
memcpy(saved_command_line, from, COMMAND_LINE_SIZE);
saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
setup_mem(from, memory_start_p, &memory_end);
- check_initrd(*memory_start_p, memory_end);
- init_task.mm->start_code = TASK_SIZE;
- init_task.mm->end_code = TASK_SIZE + (unsigned long) &_etext;
- init_task.mm->end_data = TASK_SIZE + (unsigned long) &_edata;
- init_task.mm->brk = TASK_SIZE + (unsigned long) &_end;
+ memory_end += PAGE_OFFSET;
- *cmdline_p = command_line;
- *memory_end_p = memory_end;
+ check_initrd(*memory_start_p, memory_end);
sprintf(system_utsname.machine, "%s%c", armidlist[armidindex].arch_vsn, endian);
sprintf(elf_platform, "%s%c", armidlist[armidindex].elf_vsn, endian);
@@ -385,6 +447,9 @@
conswitchp = &dummy_con;
#endif
#endif
+
+ *cmdline_p = command_line;
+ *memory_end_p = memory_end;
}
static const struct {
@@ -393,11 +458,12 @@
} machine_desc[] = {
{ "DEC-EBSA110", "DEC" },
{ "Acorn-RiscPC", "Acorn" },
- { "Nexus-NexusPCI", "PCI" },
+ { "unknown", "PCI" },
+ { "Nexus-FTV/PCI", "PCI" },
{ "DEC-EBSA285", "PCI" },
- { "Corel-Netwinder", "PCI/ISA" },
- { "Chalice-CATS", "PCI" },
- { "unknown-TBOX", "PCI" }
+ { "Corel-NetWinder", "PCI/ISA" },
+ { "Chalice-CATS", "PCI/ISA" },
+ { "unknown-TBOX", "none" }
};
#if defined(CONFIG_ARCH_ARC)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/signal.c linux.ac/arch/arm/kernel/signal.c
--- linux.vanilla/arch/arm/kernel/signal.c Sun Nov 8 15:08:43 1998
+++ linux.ac/arch/arm/kernel/signal.c Fri Jan 15 22:25:42 1999
@@ -28,7 +28,7 @@
asmlinkage int sys_wait4(pid_t pid, unsigned long * stat_addr,
int options, unsigned long *ru);
-asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs);
+asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall);
extern int ptrace_cancel_bpt (struct task_struct *);
extern int ptrace_set_bpt (struct task_struct *);
@@ -50,7 +50,7 @@
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
- if (do_signal(&saveset, regs))
+ if (do_signal(&saveset, regs, 0))
return regs->ARM_r0;
}
}
@@ -78,7 +78,7 @@
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
- if (do_signal(&saveset, regs))
+ if (do_signal(&saveset, regs, 0))
return regs->ARM_r0;
}
}
@@ -260,6 +260,18 @@
return err;
}
+static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
+ unsigned long framesize)
+{
+ unsigned long sp = regs->ARM_sp;
+
+ /* This is the X/Open sanctioned signal stack switching. */
+ if ((ka->sa.sa_flags & SA_ONSTACK) && ! on_sig_stack(sp))
+ sp = current->sas_ss_sp + current->sas_ss_size;
+
+ return (void *)(sp - framesize);
+}
+
static void setup_frame(int sig, struct k_sigaction *ka,
sigset_t *set, struct pt_regs *regs)
{
@@ -267,9 +279,9 @@
unsigned long retcode;
int err = 0;
- frame = (struct sigframe *)regs->ARM_sp - 1;
+ frame = get_sigframe(ka, regs, sizeof(*frame));
- if (!access_ok(VERIFT_WRITE, frame, sizeof (*frame)))
+ if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
goto segv_and_exit;
err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]);
@@ -299,6 +311,11 @@
regs->ARM_sp = (unsigned long)frame;
regs->ARM_lr = retcode;
regs->ARM_pc = (unsigned long)ka->sa.sa_handler;
+#if defined(CONFIG_CPU_32)
+ /* Maybe we need to deliver a 32-bit signal to a 26-bit task. */
+ if (ka->sa.sa_flags & SA_THIRTYTWO)
+ regs->ARM_cpsr = USR_MODE;
+#endif
if (valid_user_regs(regs))
return;
@@ -315,7 +332,8 @@
unsigned long retcode;
int err = 0;
- frame = (struct rt_sigframe *)regs->ARM_sp - 1;
+ frame = get_sigframe(ka, regs, sizeof(struct rt_sigframe));
+
if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
goto segv_and_exit;
@@ -350,6 +368,11 @@
regs->ARM_sp = (unsigned long)frame;
regs->ARM_lr = retcode;
regs->ARM_pc = (unsigned long)ka->sa.sa_handler;
+#if defined(CONFIG_CPU_32)
+ /* Maybe we need to deliver a 32-bit signal to a 26-bit task. */
+ if (ka->sa.sa_flags & SA_THIRTYTWO)
+ regs->ARM_cpsr = USR_MODE;
+#endif
if (valid_user_regs(regs))
return;
@@ -393,18 +416,19 @@
* the kernel can handle, and then we build all the user-level signal handling
* stack-frames in one go after that.
*/
-asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
+asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
{
- unsigned long instr, *pc = (unsigned long *)(instruction_pointer(regs)-4);
struct k_sigaction *ka;
siginfo_t info;
- int single_stepping, swi_instr;
+ int single_stepping;
+
+ if (!user_mode(regs))
+ return 0;
if (!oldset)
oldset = ¤t->blocked;
single_stepping = ptrace_cancel_bpt (current);
- swi_instr = (!get_user (instr, pc) && (instr & 0x0f000000) == 0x0f000000);
for (;;) {
unsigned long signr;
@@ -503,7 +527,7 @@
}
/* Are we from a system call? */
- if (swi_instr) {
+ if (syscall) {
switch (regs->ARM_r0) {
case -ERESTARTNOHAND:
regs->ARM_r0 = -EINTR;
@@ -527,7 +551,7 @@
return 1;
}
- if (swi_instr &&
+ if (syscall &&
(regs->ARM_r0 == -ERESTARTNOHAND ||
regs->ARM_r0 == -ERESTARTSYS ||
regs->ARM_r0 == -ERESTARTNOINTR)) {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/sys_arm.c linux.ac/arch/arm/kernel/sys_arm.c
--- linux.vanilla/arch/arm/kernel/sys_arm.c Tue Dec 22 23:19:27 1998
+++ linux.ac/arch/arm/kernel/sys_arm.c Sun Feb 7 17:47:11 1999
@@ -221,13 +221,7 @@
*/
asmlinkage int sys_fork(struct pt_regs *regs)
{
- int ret;
-
- lock_kernel();
- ret = do_fork(SIGCHLD, regs->ARM_sp, regs);
- unlock_kernel();
-
- return ret;
+ return do_fork(SIGCHLD, regs->ARM_sp, regs);
}
/* Clone a task - this clones the calling program thread.
@@ -235,14 +229,14 @@
*/
asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, struct pt_regs *regs)
{
- int ret;
-
- lock_kernel();
if (!newsp)
newsp = regs->ARM_sp;
- ret = do_fork(clone_flags, newsp, regs);
- unlock_kernel();
- return ret;
+ return do_fork(clone_flags, newsp, regs);
+}
+
+asmlinkage int sys_vfork(struct pt_regs *regs)
+{
+ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->ARM_sp, regs);
}
/* sys_execve() executes a new program.
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/time.c linux.ac/arch/arm/kernel/time.c
--- linux.vanilla/arch/arm/kernel/time.c Sun Jan 24 19:55:30 1999
+++ linux.ac/arch/arm/kernel/time.c Fri Jan 22 10:49:32 1999
@@ -130,27 +130,12 @@
time_state = TIME_ERROR; /* p. 24, (a) */
time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT;
- sti ();
+ sti();
}
-/*
- * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick.
- */
-static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- if (reset_timer ())
- do_timer(regs);
-
- update_rtc ();
-}
-
-static struct irqaction irqtimer = { timer_interrupt, 0, 0, "timer", NULL, NULL};
-
__initfunc(void time_init(void))
{
- xtime.tv_sec = setup_timer();
xtime.tv_usec = 0;
- setup_arm_irq(IRQ_TIMER, &irqtimer);
+ setup_timer();
}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/traps.c linux.ac/arch/arm/kernel/traps.c
--- linux.vanilla/arch/arm/kernel/traps.c Tue Dec 22 23:19:27 1998
+++ linux.ac/arch/arm/kernel/traps.c Fri Jan 22 09:09:37 1999
@@ -54,7 +54,7 @@
if (stackptr < PAGE_OFFSET || stackptr + size > (unsigned long)high_memory)
return -EFAULT;
#endif
- return 0;
+ return 0;
}
/*
@@ -199,9 +199,8 @@
void bad_user_access_alignment (const void *ptr)
{
- void *pc;
- __asm__("mov %0, lr\n": "=r" (pc));
- printk (KERN_ERR "bad_user_access_alignment called: ptr = %p, pc = %p\n", ptr, pc);
+ printk (KERN_ERR "bad_user_access_alignment called: ptr = %p, pc = %p\n", ptr,
+ __builtin_return_address(0));
current->tss.error_code = 0;
current->tss.trap_no = 11;
force_sig (SIGBUS, current);
@@ -210,6 +209,10 @@
asmlinkage void do_undefinstr (int address, struct pt_regs *regs, int mode)
{
+#ifdef CONFIG_DEBUG_USER
+ printk(KERN_INFO "%s (%d): undefined instruction: pc=%08lx\n",
+ current->comm, current->pid, instruction_pointer(regs));
+#endif
current->tss.error_code = 0;
current->tss.trap_no = 6;
force_sig (SIGILL, current);
@@ -218,6 +221,10 @@
asmlinkage void do_excpt (int address, struct pt_regs *regs, int mode)
{
+#ifdef CONFIG_DEBUG_USER
+ printk(KERN_INFO "%s (%d): address exception: pc=%08lx\n",
+ current->comm, current->pid, instruction_pointer(regs));
+#endif
current->tss.error_code = 0;
current->tss.trap_no = 11;
force_sig (SIGBUS, current);
@@ -249,19 +256,14 @@
*/
asmlinkage void math_state_restore (void)
{
- current->used_math = 1;
+ current->used_math = 1;
}
-asmlinkage void arm_syscall (int no, struct pt_regs *regs)
+asmlinkage int arm_syscall (int no, struct pt_regs *regs)
{
switch (no) {
case 0: /* branch through 0 */
force_sig(SIGSEGV, current);
-// if (user_mode(regs)) {
-// dump_state("branch through zero", regs, 0);
-// if (regs->ARM_fp)
-// c_backtrace (regs->ARM_fp, processor_mode(regs));
-// }
die_if_kernel ("branch through zero", regs, 0, SIGSEGV);
break;
@@ -271,21 +273,54 @@
force_sig (SIGTRAP, current);
break;
+ case 2: /* sys_cacheflush */
+#ifdef CONFIG_CPU_32
+ /* r0 = start, r1 = length, r2 = flags */
+ processor.u.armv3v4._flush_cache_area(regs->ARM_r0,
+ regs->ARM_r1,
+ 1);
+#endif
+ break;
+
default:
+ /* Calls 9f00xx..9f07ff are defined to return -ENOSYS
+ if not implemented, rather than raising SIGILL. This
+ way the calling program can gracefully determine whether
+ a feature is supported. */
+ if (no <= 0x7ff)
+ return -ENOSYS;
+#ifdef CONFIG_DEBUG_USER
+ /* experiance shows that these seem to indicate that
+ * something catastrophic has happened
+ */
printk ("[%d] %s: arm syscall %d\n", current->pid, current->comm, no);
- force_sig (SIGILL, current);
if (user_mode(regs)) {
show_regs (regs);
c_backtrace (regs->ARM_fp, processor_mode(regs));
}
+#endif
+ force_sig (SIGILL, current);
die_if_kernel ("Oops", regs, no, SIGILL);
break;
}
+ return 0;
}
asmlinkage void deferred(int n, struct pt_regs *regs)
{
- dump_state("old system call", regs, n);
+ /* You might think just testing `handler' would be enough, but PER_LINUX
+ points it to no_lcall7 to catch undercover SVr4 binaries. Gutted. */
+ if (current->personality != PER_LINUX && current->exec_domain->handler) {
+ /* Hand it off to iBCS. The extra parameter and consequent type
+ forcing is necessary because of the weird ARM calling convention. */
+ void (*handler)(int nr, struct pt_regs *regs) = (void *)current->exec_domain->handler;
+ (*handler)(n, regs);
+ return;
+ }
+#ifdef CONFIG_DEBUG_USER
+ printk(KERN_ERR "[%d] %s: old system call.\n", current->pid,
+ current->comm);
+#endif
force_sig (SIGILL, current);
}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/lib/Makefile linux.ac/arch/arm/lib/Makefile
--- linux.vanilla/arch/arm/lib/Makefile Tue Dec 22 23:19:27 1998
+++ linux.ac/arch/arm/lib/Makefile Sun Feb 28 10:24:55 1999
@@ -6,14 +6,14 @@
L_TARGET := lib.a
L_OBJS := backtrace.o bitops.o checksum.o delay.o io.o memcpy.o \
- system.o string.o uaccess.o
+ semaphore.o string.o system.o uaccess.o
ifeq ($(PROCESSOR),armo)
L_OBJS += uaccess-armo.o
endif
ifdef CONFIG_ARCH_ACORN
- L_OBJS += loaders.o ll_char_wr.o io-acorn.o
+ L_OBJS += loaders.o io-acorn.o
ifdef CONFIG_ARCH_A5K
L_OBJS += floppydma.o
endif
@@ -24,10 +24,6 @@
ifeq ($(MACHINE),ebsa110)
L_OBJS += io-ebsa110.o
-endif
-
-ifeq ($(MACHINE),vnc)
- L_OBJS += io-ebsa285.o
endif
ifeq ($(MACHINE),ebsa285)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/lib/checksum.S linux.ac/arch/arm/lib/checksum.S
--- linux.vanilla/arch/arm/lib/checksum.S Sun Nov 8 15:08:44 1998
+++ linux.ac/arch/arm/lib/checksum.S Thu Dec 10 20:14:34 1998
@@ -520,13 +520,13 @@
LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc})
ldr r4, [r0], #4
tst r2, #2
- beq Lexit
+ beq Lexit_r4
adcs r3, r3, r4, lsl #16
strb r4, [r1], #1
mov r4, r4, lsr #8
strb r4, [r1], #1
mov r4, r4, lsr #8
- b Lexit
+ b Lexit_r4
Ltoo_small: teq r2, #0
LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc})
@@ -538,10 +538,12 @@
adds r3, r3, ip
strb ip, [r1], #1
strb r8, [r1], #1
-Lexit: tst r2, #1
-Ltoo_small1: ldrneb ip, [r0], #1
- strneb ip, [r1], #1
- adcnes r3, r3, ip
+ tst r2, #1
+Ltoo_small1: ldrneb r4, [r0], #1
+Lexit_r4: tst r2, #1
+ strneb r4, [r1], #1
+ andne r4, r4, #255
+ adcnes r3, r3, r4
adcs r0, r3, #0
LOADREGS(ea,fp,{r4 - r8, fp, sp, pc})
@@ -598,13 +600,13 @@
adceq r0, r3, #0
LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc})
tst r2, #2
- beq Lexit
+ beq Lexit_r4
adcs r3, r3, r4, lsl #16
strb r4, [r1], #1
mov r4, r4, lsr #8
strb r4, [r1], #1
mov r4, r4, lsr #8
- b Lexit
+ b Lexit_r4
Lsrc2_aligned: mov r4, r4, lsr #16
adds r3, r3, #0
@@ -650,13 +652,13 @@
adceq r0, r3, #0
LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc})
tst r2, #2
- beq Lexit
+ beq Lexit_r4
adcs r3, r3, r4, lsl #16
strb r4, [r1], #1
mov r4, r4, lsr #8
strb r4, [r1], #1
ldrb r4, [r0], #1
- b Lexit
+ b Lexit_r4
Lsrc3_aligned: mov r4, r4, lsr #24
adds r3, r3, #0
@@ -702,14 +704,14 @@
adceq r0, r3, #0
LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc})
tst r2, #2
- beq Lexit
+ beq Lexit_r4
adcs r3, r3, r4, lsl #16
strb r4, [r1], #1
ldr r4, [r0], #4
strb r4, [r1], #1
adcs r3, r3, r4, lsl #24
mov r4, r4, lsr #8
- b Lexit
+ b Lexit_r4
ENTRY(__csum_ipv6_magic)
stmfd sp!, {lr}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/lib/floppydma.S linux.ac/arch/arm/lib/floppydma.S
--- linux.vanilla/arch/arm/lib/floppydma.S Sun Nov 8 15:08:44 1998
+++ linux.ac/arch/arm/lib/floppydma.S Tue Feb 2 20:31:32 1999
@@ -26,32 +26,3 @@
strb r12, [r11, #-4]
subs pc, lr, #4
SYMBOL_NAME(floppy_fiqout_end):
-
-@ Params:
-@ r0 = length
-@ r1 = address
-@ r2 = floppy port
-@ Puts these into R9_fiq, R10_fiq, R11_fiq
-ENTRY(floppy_fiqsetup)
- mov ip, sp
- stmfd sp!, {fp, ip, lr, pc}
- sub fp, ip, #4
- MODE(r3,ip,I_BIT|F_BIT|DEFAULT_FIQ) @ disable FIQs, IRQs, FIQ mode
- mov r0, r0
- mov r9, r0
- mov r10, r1
- mov r11, r2
- RESTOREMODE(r3) @ back to normal
- mov r0, r0
- LOADREGS(ea,fp,{fp, sp, pc})
-
-ENTRY(floppy_fiqresidual)
- mov ip, sp
- stmfd sp!, {fp, ip, lr, pc}
- sub fp, ip, #4
- MODE(r3,ip,I_BIT|F_BIT|DEFAULT_FIQ) @ disable FIQs, IRQs, FIQ mode
- mov r0, r0
- mov r0, r9
- RESTOREMODE(r3)
- mov r0, r0
- LOADREGS(ea,fp,{fp, sp, pc})
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/lib/io-acorn.S linux.ac/arch/arm/lib/io-acorn.S
--- linux.vanilla/arch/arm/lib/io-acorn.S Sun Nov 8 15:08:44 1998
+++ linux.ac/arch/arm/lib/io-acorn.S Sun Feb 28 19:12:36 1999
@@ -11,50 +11,514 @@
.text
.align
-#define OUT(reg) \
- mov r8, reg, lsl $16 ;\
- orr r8, r8, r8, lsr $16 ;\
- str r8, [r3, r0, lsl $2] ;\
- mov r8, reg, lsr $16 ;\
- orr r8, r8, r8, lsl $16 ;\
- str r8, [r3, r0, lsl $2]
-
-#define IN(reg) \
- ldr reg, [r0] ;\
- and reg, reg, ip ;\
- ldr lr, [r0] ;\
- orr reg, reg, lr, lsl $16
-
- .equ pcio_base_high, PCIO_BASE & 0xff000000
- .equ pcio_base_low, PCIO_BASE & 0x00ff0000
- .equ io_base_high, IO_BASE & 0xff000000
- .equ io_base_low, IO_BASE & 0x00ff0000
-
- .equ addr_io_diff_hi, pcio_base_high - io_base_high
- .equ addr_io_diff_lo, pcio_base_low - io_base_low
-
- .macro addr reg, off
- tst \off, #0x80000000
- .if addr_io_diff_hi
- movne \reg, #IO_BASE
- moveq \reg, #pcio_base_high
- .if pcio_base_low
- addeq \reg, \reg, #pcio_base_low
- .endif
- .else
- mov \reg, #IO_BASE
- addeq \reg, \reg, #addr_io_diff_lo
- .endif
+ .equ diff_pcio_base, PCIO_BASE - IO_BASE
+
+ .macro outw2 rd
+ mov r8, \rd, lsl #16
+ orr r8, r8, r8, lsr #16
+ str r8, [r3, r0, lsl #2]
+ mov r8, \rd, lsr #16
+ orr r8, r8, r8, lsl #16
+ str r8, [r3, r0, lsl #2]
+ .endm
+
+ .macro inw2 rd, mask, temp
+ ldr \rd, [r0]
+ and \rd, \rd, \mask
+ ldr \temp, [r0]
+ orr \rd, \rd, \temp, lsl #16
+ .endm
+
+ .macro addr rd
+ tst \rd, #0x80000000
+ mov \rd, \rd, lsl #2
+ add \rd, \rd, #IO_BASE
+ addeq \rd, \rd, #diff_pcio_base
.endm
-@ Purpose: read a block of data from a hardware register to memory.
-@ Proto : insw(int from_port, void *to, int len_in_words);
-@ Proto : inswb(int from_port, void *to, int len_in_bytes);
-@ Notes : increment to
+.iosw_bad_align_msg:
+ .ascii "insw: bad buffer alignment (%p), called from %08lX\n\0"
+.iosl_warning:
+ .ascii "<4>insl/outsl not implemented, called from %08lX\0"
+ .align
+
+/*
+ * These make no sense on Acorn machines.
+ * Print a warning message.
+ */
+ENTRY(insl)
+ENTRY(outsl)
+ adr r0, .iosl_warning
+ mov r1, lr
+ b SYMBOL_NAME(printk)
+
+.iosw_bad_alignment:
+ adr r0, .iosw_bad_align_msg
+ mov r2, lr
+ b SYMBOL_NAME(panic)
+
+
+/* Purpose: read a block of data from a hardware register to memory.
+ * Proto : void insw(int from_port, void *to, int len_in_words);
+ * Notes : increment to, 'to' must be 16-bit aligned
+ */
+
+.insw_align: tst r1, #1
+ bne .iosw_bad_alignment
+
+ ldr r3, [r0]
+ strb r3, [r1], #1
+ mov r3, r3, lsr #8
+ strb r3, [r1], #1
+
+ subs r2, r2, #1
+ bne .insw_aligned
ENTRY(insw)
+ teq r2, #0
+ RETINSTR(moveq,pc,lr)
+ addr r0
+ tst r1, #3
+ bne .insw_align
+
+.insw_aligned: mov ip, #0xff
+ orr ip, ip, ip, lsl #8
+ stmfd sp!, {r4, r5, r6, lr}
+
+ subs r2, r2, #8
+ bmi .no_insw_8
+
+.insw_8_lp: ldr r3, [r0]
+ and r3, r3, ip
+ ldr r4, [r0]
+ orr r3, r3, r4, lsl #16
+
+ ldr r4, [r0]
+ and r4, r4, ip
+ ldr r5, [r0]
+ orr r4, r4, r5, lsl #16
+
+ ldr r5, [r0]
+ and r5, r5, ip
+ ldr r6, [r0]
+ orr r5, r5, r6, lsl #16
+
+ ldr r6, [r0]
+ and r6, r6, ip
+ ldr lr, [r0]
+ orr r6, r6, lr, lsl #16
+
+ stmia r1!, {r3 - r6}
+ subs r2, r2, #8
+ bpl .insw_8_lp
+ tst r2, #7
+ LOADREGS(eqfd, sp!, {r4, r5, r6, pc})
+
+.no_insw_8: tst r2, #4
+ beq .no_insw_4
+
+ ldr r3, [r0]
+ and r3, r3, ip
+ ldr r4, [r0]
+ orr r3, r3, r4, lsl #16
+
+ ldr r4, [r0]
+ and r4, r4, ip
+ ldr r5, [r0]
+ orr r4, r4, r5, lsl #16
+
+ stmia r1!, {r3, r4}
+
+.no_insw_4: tst r2, #2
+ beq .no_insw_2
+
+ ldr r3, [r0]
+ and r3, r3, ip
+ ldr r4, [r0]
+ orr r3, r3, r4, lsl #16
+
+ str r3, [r1], #4
+
+.no_insw_2: tst r2, #1
+ ldrne r3, [r0]
+ strneb r3, [r1], #1
+ movne r3, r3, lsr #8
+ strneb r3, [r1]
+ LOADREGS(fd, sp!, {r4, r5, r6, pc})
+
+@ Purpose: write a block of data from memory to a hardware register.
+@ Proto : outsw(int to_reg, void *from, int len_in_words);
+@ Notes : increments from
+
+.outsw_align: tst r1, #1
+ bne .iosw_bad_alignment
+
+ add r1, r1, #2
+
+ ldr r3, [r1, #-4]
+ mov r3, r3, lsr #16
+ orr r3, r3, r3, lsl #16
+ str r3, [r0]
+ subs r2, r2, #1
+ bne .outsw_aligned
+
+ENTRY(outsw)
+ teq r2, #0
+ RETINSTR(moveq,pc,lr)
+ addr r0
+ tst r1, #3
+ bne .outsw_align
+
+.outsw_aligned: stmfd sp!, {r4, r5, r6, lr}
+
+ subs r2, r2, #8
+ bmi .no_outsw_8
+.outsw_8_lp: ldmia r1!, {r3, r4, r5, r6}
+
+ mov ip, r3, lsl #16
+ orr ip, ip, ip, lsr #16
+ str ip, [r0]
+
+ mov ip, r3, lsr #16
+ orr ip, ip, ip, lsl #16
+ str ip, [r0]
+
+ mov ip, r4, lsl #16
+ orr ip, ip, ip, lsr #16
+ str ip, [r0]
+
+ mov ip, r4, lsr #16
+ orr ip, ip, ip, lsl #16
+ str ip, [r0]
+
+ mov ip, r5, lsl #16
+ orr ip, ip, ip, lsr #16
+ str ip, [r0]
+
+ mov ip, r5, lsr #16
+ orr ip, ip, ip, lsl #16
+ str ip, [r0]
+
+ mov ip, r6, lsl #16
+ orr ip, ip, ip, lsr #16
+ str ip, [r0]
+
+ mov ip, r6, lsr #16
+ orr ip, ip, ip, lsl #16
+ str ip, [r0]
+
+ subs r2, r2, #8
+ bpl .outsw_8_lp
+ tst r2, #7
+ LOADREGS(eqfd, sp!, {r4, r5, r6, pc})
+
+.no_outsw_8: tst r2, #4
+ beq .no_outsw_4
+
+ ldmia r1!, {r3, r4}
+
+ mov ip, r3, lsl #16
+ orr ip, ip, ip, lsr #16
+ str ip, [r0]
+
+ mov ip, r3, lsr #16
+ orr ip, ip, ip, lsl #16
+ str ip, [r0]
+
+ mov ip, r4, lsl #16
+ orr ip, ip, ip, lsr #16
+ str ip, [r0]
+
+ mov ip, r4, lsr #16
+ orr ip, ip, ip, lsl #16
+ str ip, [r0]
+
+.no_outsw_4: tst r2, #2
+ beq .no_outsw_2
+
+ ldr r3, [r1], #4
+
+ mov ip, r3, lsl #16
+ orr ip, ip, ip, lsr #16
+ str ip, [r0]
+
+ mov ip, r3, lsr #16
+ orr ip, ip, ip, lsl #16
+ str ip, [r0]
+
+.no_outsw_2: tst r2, #1
+
+ ldrne r3, [r1]
+
+ movne ip, r3, lsl #16
+ orrne ip, ip, ip, lsr #16
+ strne ip, [r0]
+
+ LOADREGS(fd, sp!, {r4, r5, r6, pc})
+
+.insb_align: rsb ip, ip, #4
+ cmp ip, r2
+ movgt ip, r2
+ cmp ip, #2
+ ldrb r3, [r0]
+ strb r3, [r1], #1
+ ldrgeb r3, [r0]
+ strgeb r3, [r1], #1
+ ldrgtb r3, [r0]
+ strgtb r3, [r1], #1
+ subs r2, r2, ip
+ bne .insb_aligned
+
+ENTRY(insb)
+ teq r2, #0
+ moveq pc, lr
+ addr r0
+ ands ip, r1, #3
+ bne .insb_align
+
+.insb_aligned: stmfd sp!, {r4 - r6, lr}
+
+ subs r2, r2, #16
+ bmi .insb_no_16
+
+.insb_16_lp: ldrb r3, [r0]
+ ldrb r4, [r0]
+ orr r3, r3, r4, lsl #8
+ ldrb r4, [r0]
+ orr r3, r3, r4, lsl #16
+ ldrb r4, [r0]
+ orr r3, r3, r4, lsl #24
+ ldrb r4, [r0]
+ ldrb r5, [r0]
+ orr r4, r4, r5, lsl #8
+ ldrb r5, [r0]
+ orr r4, r4, r5, lsl #16
+ ldrb r5, [r0]
+ orr r4, r4, r5, lsl #24
+ ldrb r5, [r0]
+ ldrb r6, [r0]
+ orr r5, r5, r6, lsl #8
+ ldrb r6, [r0]
+ orr r5, r5, r6, lsl #16
+ ldrb r6, [r0]
+ orr r5, r5, r6, lsl #24
+ ldrb r6, [r0]
+ ldrb ip, [r0]
+ orr r6, r6, ip, lsl #8
+ ldrb ip, [r0]
+ orr r6, r6, ip, lsl #16
+ ldrb ip, [r0]
+ orr r6, r6, ip, lsl #24
+ stmia r1!, {r3 - r6}
+ subs r2, r2, #16
+ bpl .insb_16_lp
+
+ tst r2, #15
+ LOADREGS(eqfd, sp!, {r4 - r6, pc})
+
+.insb_no_16: tst r2, #8
+ beq .insb_no_8
+
+ ldrb r3, [r0]
+ ldrb r4, [r0]
+ orr r3, r3, r4, lsl #8
+ ldrb r4, [r0]
+ orr r3, r3, r4, lsl #16
+ ldrb r4, [r0]
+ orr r3, r3, r4, lsl #24
+ ldrb r4, [r0]
+ ldrb r5, [r0]
+ orr r4, r4, r5, lsl #8
+ ldrb r5, [r0]
+ orr r4, r4, r5, lsl #16
+ ldrb r5, [r0]
+ orr r4, r4, r5, lsl #24
+ stmia r1!, {r3, r4}
+
+.insb_no_8: tst r2, #4
+ bne .insb_no_4
+
+ ldrb r3, [r0]
+ ldrb r4, [r0]
+ orr r3, r3, r4, lsl #8
+ ldrb r4, [r0]
+ orr r3, r3, r4, lsl #16
+ ldrb r4, [r0]
+ orr r3, r3, r4, lsl #24
+ str r3, [r1], #4
+
+.insb_no_4: ands r2, r2, #3
+ LOADREGS(eqfd, sp!, {r4 - r6, pc})
+ cmp r2, #2
+ ldrb r3, [r0]
+ strb r3, [r1], #1
+ ldrgeb r3, [r0]
+ strgeb r3, [r1], #1
+ ldrgtb r3, [r0]
+ strgtb r3, [r1]
+ LOADREGS(fd, sp!, {r4 - r6, pc})
+
+
+
+.outsb_align: rsb ip, ip, #4
+ cmp ip, r2
+ mov ip, r2
+ cmp ip, #2
+ ldrb r3, [r1], #1
+ strb r3, [r0]
+ ldrgeb r3, [r1], #1
+ strgeb r3, [r0]
+ ldrgtb r3, [r1], #1
+ strgtb r3, [r0]
+ subs r2, r2, ip
+ bne .outsb_aligned
+
+ENTRY(outsb)
+ teq r2, #0
+ moveq pc, lr
+ addr r0
+ ands ip, r1, #3
+ bne .outsb_align
+
+.outsb_aligned: stmfd sp!, {r4 - r6, lr}
+
+ subs r2, r2, #16
+ bmi .outsb_no_16
+
+.outsb_16_lp: ldmia r1!, {r3 - r6}
+ strb r3, [r0]
+ mov r3, r3, lsr #8
+ strb r3, [r0]
+ mov r3, r3, lsr #8
+ strb r3, [r0]
+ mov r3, r3, lsr #8
+ strb r3, [r0]
+
+ strb r4, [r0]
+ mov r4, r4, lsr #8
+ strb r4, [r0]
+ mov r4, r4, lsr #8
+ strb r4, [r0]
+ mov r4, r4, lsr #8
+ strb r4, [r0]
+
+ strb r5, [r0]
+ mov r5, r5, lsr #8
+ strb r5, [r0]
+ mov r5, r5, lsr #8
+ strb r5, [r0]
+ mov r5, r5, lsr #8
+ strb r5, [r0]
+
+ strb r6, [r0]
+ mov r6, r6, lsr #8
+ strb r6, [r0]
+ mov r6, r6, lsr #8
+ strb r6, [r0]
+ mov r6, r6, lsr #8
+ strb r6, [r0]
+ subs r2, r2, #16
+ bpl .outsb_16_lp
+
+ tst r2, #15
+ LOADREGS(eqfd, sp!, {r4 - r6, pc})
+
+.outsb_no_16: tst r2, #8
+ beq .outsb_no_8
+
+ ldmia r1, {r3, r4}
+ strb r3, [r0]
+ mov r3, r3, lsr #8
+ strb r3, [r0]
+ mov r3, r3, lsr #8
+ strb r3, [r0]
+ mov r3, r3, lsr #8
+ strb r3, [r0]
+
+ strb r4, [r0]
+ mov r4, r4, lsr #8
+ strb r4, [r0]
+ mov r4, r4, lsr #8
+ strb r4, [r0]
+ mov r4, r4, lsr #8
+ strb r4, [r0]
+
+.outsb_no_8: tst r2, #4
+ bne .outsb_no_4
+
+ ldr r3, [r1], #4
+ strb r3, [r0]
+ mov r3, r3, lsr #8
+ strb r3, [r0]
+ mov r3, r3, lsr #8
+ strb r3, [r0]
+ mov r3, r3, lsr #8
+ strb r3, [r0]
+
+.outsb_no_4: ands r2, r2, #3
+ LOADREGS(eqfd, sp!, {r4 - r6, pc})
+ cmp r2, #2
+ ldrb r3, [r1], #1
+ strb r3, [r0]
+ ldrgeb r3, [r1], #1
+ strgeb r3, [r0]
+ ldrgtb r3, [r1]
+ strgtb r3, [r0]
+ LOADREGS(fd, sp!, {r4 - r6, pc})
+
+
+
+
+@ Purpose: write a memc register
+@ Proto : void memc_write(int register, int value);
+@ Returns: nothing
+
+#if defined(CONFIG_CPU_26)
+ENTRY(memc_write)
+ cmp r0, #7
+ RETINSTR(movgt,pc,lr)
+ mov r0, r0, lsl #17
+ mov r1, r1, lsl #15
+ mov r1, r1, lsr #17
+ orr r0, r0, r1, lsl #2
+ add r0, r0, #0x03600000
+ strb r0, [r0]
+ RETINSTR(mov,pc,lr)
+#define CPSR2SPSR(rt)
+#else
+#define CPSR2SPSR(rt) \
+ mrs rt, cpsr; \
+ msr spsr, rt
+#endif
+
+@ Purpose: call an expansion card loader to read bytes.
+@ Proto : char read_loader(int offset, char *card_base, char *loader);
+@ Returns: byte read
+
+ENTRY(ecard_loader_read)
+ stmfd sp!, {r4 - r12, lr}
+ mov r11, r1
+ mov r1, r0
+ CPSR2SPSR(r0)
+ mov lr, pc
+ mov pc, r2
+ LOADREGS(fd, sp!, {r4 - r12, pc})
+
+@ Purpose: call an expansion card loader to reset the card
+@ Proto : void read_loader(int card_base, char *loader);
+@ Returns: byte read
+
+ENTRY(ecard_loader_reset)
+ stmfd sp!, {r4 - r12, lr}
+ mov r11, r0
+ CPSR2SPSR(r0)
+ mov lr, pc
+ add pc, r1, #8
+ LOADREGS(fd, sp!, {r4 - r12, pc})
+
+
+#if 0
mov r2, r2, lsl#1
-ENTRY(inswb)
mov ip, sp
stmfd sp!, {r4 - r10, fp, ip, lr, pc}
sub fp, ip, #4
@@ -122,14 +586,9 @@
bgt Linsw_notaligned
LOADREGS(ea, fp, {r4 - r10, fp, sp, pc})
-@ Purpose: write a block of data from memory to a hardware register.
-@ Proto : outsw(int to_reg, void *from, int len_in_words);
-@ Proto : outswb(int to_reg, void *from, int len_in_bytes);
-@ Notes : increments from
ENTRY(outsw)
- mov r2, r2, LSL#1
-ENTRY(outswb)
+ mov r2, r2, lsl#1
mov ip, sp
stmfd sp!, {r4 - r8, fp, ip, lr, pc}
sub fp, ip, #4
@@ -166,56 +625,5 @@
bgt 3b
LOADREGS(ea, fp, {r4 - r8, fp, sp, pc})
-/*
- * These make no sense on Acorn machines atm.
- */
-ENTRY(insl)
-ENTRY(outsl)
- RETINSTR(mov,pc,lr)
-
-@ Purpose: write a memc register
-@ Proto : void memc_write(int register, int value);
-@ Returns: nothing
-
-#if defined(CONFIG_CPU_26)
-ENTRY(memc_write)
- cmp r0, #7
- RETINSTR(movgt,pc,lr)
- mov r0, r0, lsl #17
- mov r1, r1, lsl #15
- mov r1, r1, lsr #17
- orr r0, r0, r1, lsl #2
- add r0, r0, #0x03600000
- strb r0, [r0]
- RETINSTR(mov,pc,lr)
-#define CPSR2SPSR(rt)
-#else
-#define CPSR2SPSR(rt) \
- mrs rt, cpsr; \
- msr spsr, rt
#endif
-@ Purpose: call an expansion card loader to read bytes.
-@ Proto : char read_loader(int offset, char *card_base, char *loader);
-@ Returns: byte read
-
-ENTRY(ecard_loader_read)
- stmfd sp!, {r4 - r12, lr}
- mov r11, r1
- mov r1, r0
- CPSR2SPSR(r0)
- mov lr, pc
- mov pc, r2
- LOADREGS(fd, sp!, {r4 - r12, pc})
-
-@ Purpose: call an expansion card loader to reset the card
-@ Proto : void read_loader(int card_base, char *loader);
-@ Returns: byte read
-
-ENTRY(ecard_loader_reset)
- stmfd sp!, {r4 - r12, lr}
- mov r11, r0
- CPSR2SPSR(r0)
- mov lr, pc
- add pc, r1, #8
- LOADREGS(fd, sp!, {r4 - r12, pc})
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/lib/io-ebsa110.S linux.ac/arch/arm/lib/io-ebsa110.S
--- linux.vanilla/arch/arm/lib/io-ebsa110.S Sun Nov 8 15:08:44 1998
+++ linux.ac/arch/arm/lib/io-ebsa110.S Sun Feb 28 21:08:34 1999
@@ -22,6 +22,22 @@
ldr lr, [r0] ;\
orr reg, reg, lr, lsl $16
+/*
+ * These make no sense on these machines.
+ * Print a warning message.
+ */
+ENTRY(insl)
+ENTRY(outsl)
+ENTRY(insb)
+ENTRY(outsb)
+ adr r0, io_long_warning
+ mov r1, lr
+ b SYMBOL_NAME(printk)
+
+io_long_warning:
+ .ascii "<4>ins?/outs? not implemented on this architecture\0"
+ .align
+
@ Purpose: read a block of data from a hardware register to memory.
@ Proto : insw(int from_port, void *to, int len_in_words);
@ Proto : inswb(int from_port, void *to, int len_in_bytes);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/lib/io-ebsa285.S linux.ac/arch/arm/lib/io-ebsa285.S
--- linux.vanilla/arch/arm/lib/io-ebsa285.S Tue Dec 22 23:19:27 1998
+++ linux.ac/arch/arm/lib/io-ebsa285.S Fri Jan 15 19:12:00 1999
@@ -1,8 +1,12 @@
#include
+ .macro ioaddr, rd,rn
+ add \rd, \rn, #0xff000000
+ add \rd, \rd, #0x00e00000
+ .endm
+
ENTRY(insl)
- add r0, r0, #0xff000000
- add r0, r0, #0x00e00000
+ ioaddr r0, r0
ands ip, r1, #3
bne 2f
@@ -14,49 +18,48 @@
2: cmp ip, #2
ldr ip, [r0]
- blt 3f
- bgt 4f
+ blt 4f
+ bgt 6f
strh ip, [r1], #2
mov ip, ip, lsr #16
-1: subs r2, r2, #1
+3: subs r2, r2, #1
ldrne r3, [r0]
orrne ip, ip, r3, lsl #16
strne ip, [r1], #4
movne ip, r3, lsr #16
- bne 1b
+ bne 3b
strh ip, [r1], #2
mov pc, lr
-3: strb ip, [r1], #1
+4: strb ip, [r1], #1
mov ip, ip, lsr #8
strh ip, [r1], #2
mov ip, ip, lsr #16
-1: subs r2, r2, #1
+5: subs r2, r2, #1
ldrne r3, [r0]
orrne ip, ip, r3, lsl #8
strne ip, [r1], #4
movne ip, r3, lsr #24
- bne 1b
+ bne 5b
strb ip, [r1], #1
mov pc, lr
-4: strb ip, [r1], #1
+6: strb ip, [r1], #1
mov ip, ip, lsr #8
-1: subs r2, r2, #1
+7: subs r2, r2, #1
ldrne r3, [r0]
orrne ip, ip, r3, lsl #24
strne ip, [r1], #4
movne ip, r3, lsr #8
- bne 1b
+ bne 7b
strb ip, [r1], #1
mov ip, ip, lsr #8
strh ip, [r1], #2
mov pc, lr
ENTRY(outsl)
- add r0, r0, #0xff000000
- add r0, r0, #0x00e00000
+ ioaddr r0, r0
ands ip, r1, #3
bne 2f
@@ -70,31 +73,31 @@
cmp ip, #2
ldr ip, [r1], #4
mov ip, ip, lsr #16
- blt 3f
- bgt 4f
+ blt 4f
+ bgt 5f
-1: ldr r3, [r1], #4
+3: ldr r3, [r1], #4
orr ip, ip, r3, lsl #16
str ip, [r0]
mov ip, r3, lsr #16
subs r2, r2, #1
- bne 1b
+ bne 3b
mov pc, lr
-3: ldr r3, [r1], #4
+4: ldr r3, [r1], #4
orr ip, ip, r3, lsl #8
str ip, [r0]
mov ip, r3, lsr #24
subs r2, r2, #1
- bne 3b
+ bne 4b
mov pc, lr
-4: ldr r3, [r1], #4
+5: ldr r3, [r1], #4
orr ip, ip, r3, lsl #24
str ip, [r0]
mov ip, r3, lsr #8
subs r2, r2, #1
- bne 4b
+ bne 5b
mov pc, lr
/* Nobody could say these are optimal, but not to worry. */
@@ -102,8 +105,7 @@
ENTRY(outswb)
mov r2, r2, lsr #1
ENTRY(outsw)
- add r0, r0, #0xff000000
- add r0, r0, #0x00e00000
+ ioaddr r0, r0
1: subs r2, r2, #1
ldrgeh r3, [r1], #2
strgeh r3, [r0]
@@ -114,8 +116,7 @@
mov r2, r2, lsr #1
ENTRY(insw)
stmfd sp!, {r4, r5, lr}
- add r0, r0, #0xff000000
- add r0, r0, #0x00e00000
+ ioaddr r0, r0
@ + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17
subs ip, r2, #8
blo too_little
@@ -176,8 +177,7 @@
ENTRY(insb)
- add r0, r0, #0xff000000
- add r0, r0, #0x00e00000
+ ioaddr r0, r0
1: teq r2, #0
ldrneb r3, [r0]
strneb r3, [r1], #1
@@ -187,8 +187,7 @@
ENTRY(outsb)
- add r0, r0, #0xff000000
- add r0, r0, #0x00e00000
+ ioaddr r0, r0
1: teq r2, #0
ldrneb r3, [r1], #1
strneb r3, [r0]
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/lib/ll_char_wr.S linux.ac/arch/arm/lib/ll_char_wr.S
--- linux.vanilla/arch/arm/lib/ll_char_wr.S Sun Nov 8 15:08:44 1998
+++ linux.ac/arch/arm/lib/ll_char_wr.S Thu Jan 1 01:00:00 1970
@@ -1,158 +0,0 @@
-/*
- * linux/arch/arm/lib/ll_char_wr.S
- *
- * Copyright (C) 1995, 1996 Russell King.
- *
- * Speedups & 1bpp code (C) 1996 Philip Blundell & Russell King.
- *
- * 10-04-96 RMK Various cleanups & reduced register usage.
- * 08-04-98 RMK Shifts re-ordered
- */
-
-@ Regs: [] = corruptible
-@ {} = used
-@ () = do not use
-
-#include
-#include
- .text
-
-#define BOLD 0x01
-#define ITALIC 0x02
-#define UNDERLINE 0x04
-#define FLASH 0x08
-#define INVERSE 0x10
-
-LC0: .word SYMBOL_NAME(bytes_per_char_h)
- .word SYMBOL_NAME(video_size_row)
- .word SYMBOL_NAME(cmap_80)
- .word SYMBOL_NAME(con_charconvtable)
-
-ENTRY(ll_write_char)
- stmfd sp!, {r4 - r7, lr}
-@
-@ Smashable regs: {r0 - r3}, [r4 - r7], (r8 - fp), [ip], (sp), [lr], (pc)
-@
- eor ip, r1, #UNDERLINE << 9
-/*
- * calculate colours
- */
- tst r1, #INVERSE << 9
- moveq r2, r1, lsr #16
- moveq r3, r1, lsr #24
- movne r2, r1, lsr #24
- movne r3, r1, lsr #16
- and r3, r3, #255
- and r2, r2, #255
-/*
- * calculate offset into character table
- */
- mov r1, r1, lsl #23
- mov r1, r1, lsr #20
-/*
- * calculate offset required for each row [maybe I should make this an argument to this fn.
- * Have to see what the register usage is like in the calling routines.
- */
- adr r4, LC0
- ldmia r4, {r4, r5, r6, lr}
- ldr r4, [r4]
- ldr r5, [r5]
-/*
- * Go to resolution-dependent routine...
- */
- cmp r4, #4
- blt Lrow1bpp
- eor r2, r3, r2 @ Create eor mask to change colour from bg
- orr r3, r3, r3, lsl #8 @ to fg.
- orr r3, r3, r3, lsl #16
- add r0, r0, r5, lsl #3 @ Move to bottom of character
- add r1, r1, #7
- ldrb r7, [r6, r1]
- tst ip, #UNDERLINE << 9
- eoreq r7, r7, #255
- teq r4, #8
- beq Lrow8bpplp
-@
-@ Smashable regs: {r0 - r3}, [r4], {r5 - r7}, (r8 - fp), [ip], (sp), {lr}, (pc)
-@
- orr r3, r3, r3, lsl #4
-Lrow4bpplp: ldr r7, [lr, r7, lsl #2]
- mul r7, r2, r7
- tst r1, #7 @ avoid using r7 directly after
- eor ip, r3, r7
- str ip, [r0, -r5]!
- LOADREGS(eqfd, sp!, {r4 - r7, pc})
- sub r1, r1, #1
- ldrb r7, [r6, r1]
- ldr r7, [lr, r7, lsl #2]
- mul r7, r2, r7
- tst r1, #7 @ avoid using r7 directly after
- eor ip, r3, r7
- str ip, [r0, -r5]!
- subne r1, r1, #1
- ldrneb r7, [r6, r1]
- bne Lrow4bpplp
- LOADREGS(fd, sp!, {r4 - r7, pc})
-
-@
-@ Smashable regs: {r0 - r3}, [r4], {r5 - r7}, (r8 - fp), [ip], (sp), {lr}, (pc)
-@
-Lrow8bpplp: mov ip, r7, lsr #4
- ldr ip, [lr, ip, lsl #2]
- mul r4, r2, ip
- and ip, r7, #15 @ avoid r4
- ldr ip, [lr, ip, lsl #2] @ avoid r4
- mul ip, r2, ip @ avoid r4
- eor r4, r3, r4 @ avoid ip
- tst r1, #7 @ avoid ip
- sub r0, r0, r5 @ avoid ip
- eor ip, r3, ip
- stmia r0, {r4, ip}
- LOADREGS(eqfd, sp!, {r4 - r7, pc})
- sub r1, r1, #1
- ldrb r7, [r6, r1]
- mov ip, r7, lsr #4
- ldr ip, [lr, ip, lsl #2]
- mul r4, r2, ip
- and ip, r7, #15 @ avoid r4
- ldr ip, [lr, ip, lsl #2] @ avoid r4
- mul ip, r2, ip @ avoid r4
- eor r4, r3, r4 @ avoid ip
- tst r1, #7 @ avoid ip
- sub r0, r0, r5 @ avoid ip
- eor ip, r3, ip
- stmia r0, {r4, ip}
- subne r1, r1, #1
- ldrneb r7, [r6, r1]
- bne Lrow8bpplp
- LOADREGS(fd, sp!, {r4 - r7, pc})
-
-@
-@ Smashable regs: {r0 - r3}, [r4], {r5, r6}, [r7], (r8 - fp), [ip], (sp), [lr], (pc)
-@
-Lrow1bpp: add r6, r6, r1
- ldmia r6, {r4, r7}
- tst ip, #INVERSE << 9
- mvnne r4, r4
- mvnne r7, r7
- strb r4, [r0], r5
- mov r4, r4, lsr #8
- strb r4, [r0], r5
- mov r4, r4, lsr #8
- strb r4, [r0], r5
- mov r4, r4, lsr #8
- strb r4, [r0], r5
- strb r7, [r0], r5
- mov r7, r7, lsr #8
- strb r7, [r0], r5
- mov r7, r7, lsr #8
- strb r7, [r0], r5
- mov r7, r7, lsr #8
- tst ip, #UNDERLINE << 9
- mvneq r7, r7
- strb r7, [r0], r5
- LOADREGS(fd, sp!, {r4 - r7, pc})
-
- .bss
-ENTRY(con_charconvtable)
- .space 1024
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/lib/semaphore.S linux.ac/arch/arm/lib/semaphore.S
--- linux.vanilla/arch/arm/lib/semaphore.S Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/lib/semaphore.S Sun Jan 3 10:37:24 1999
@@ -0,0 +1,29 @@
+/*
+ * linux/arch/arm/lib/semaphore.S
+ *
+ * Idea from i386 code, Copyright Linus Torvalds.
+ * Converted for ARM by Russell King
+ */
+#include
+#include
+
+/*
+ * The semaphore operations have a special calling sequence
+ * that allows us to keep the distruption of the main code
+ * path to a minimum. These routines save and restore the
+ * registers that will be touched by __down etc.
+ */
+ENTRY(__down_failed)
+ stmfd sp!, {r0 - r3, ip, lr}
+ bl SYMBOL_NAME(__down)
+ LOADREGS(fd, sp!, {r0 - r3, ip, pc})
+
+ENTRY(__down_interruptible_failed)
+ stmfd sp!, {r1 - r3, ip, lr}
+ bl SYMBOL_NAME(__down_interruptible)
+ LOADREGS(fd, sp!, {r1 - r3, ip, pc})
+
+ENTRY(__up_wakeup)
+ stmfd sp!, {r0 - r3, ip, lr}
+ bl SYMBOL_NAME(__up)
+ LOADREGS(fd, sp!, {r0 - r3, ip, pc})
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/mm/Makefile linux.ac/arch/arm/mm/Makefile
--- linux.vanilla/arch/arm/mm/Makefile Sun Nov 8 15:08:44 1998
+++ linux.ac/arch/arm/mm/Makefile Sun Feb 7 22:59:05 1999
@@ -8,29 +8,20 @@
# Note 2! The CFLAGS definition is now in the main makefile...
all: lib first_rule
-ifeq ($(MACHINE),a5k)
-MMARCH=arc
-else
-MMARCH=$(MACHINE)
-endif
O_TARGET := mm.o
-O_OBJS := init.o extable.o fault-$(PROCESSOR).o mm-$(MMARCH).o
+O_OBJS := init.o extable.o fault-$(PROCESSOR).o small_page.o
ifeq ($(PROCESSOR),armo)
O_OBJS += proc-arm2,3.o
endif
ifeq ($(PROCESSOR),armv)
- O_OBJS += small_page.o proc-arm6,7.o proc-sa110.o
+ O_OBJS += mm-$(MACHINE).o proc-arm6,7.o proc-sa110.o ioremap.o
endif
include $(TOPDIR)/Rules.make
-proc-arm2,3.o: ../lib/constants.h
-proc-arm6,7.o: ../lib/constants.h
-proc-sa110.o: ../lib/constants.h
-
%.o: %.S
ifneq ($(CONFIG_BINUTILS_NEW),y)
$(CC) $(CFLAGS) -D__ASSEMBLY__ -E $< | tr ';$$' '\n#' > ..$@.tmp.s
@@ -42,3 +33,11 @@
.PHONY: lib
lib:; @$(MAKE) -C ../lib constants.h
+
+# Special dependencies
+fault-armv.o: fault-common.c
+fault-armo.o: fault-common.c
+proc-arm2,3.o: ../lib/constants.h
+proc-arm6,7.o: ../lib/constants.h
+proc-sa110.o: ../lib/constants.h
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/mm/fault-armo.c linux.ac/arch/arm/mm/fault-armo.c
--- linux.vanilla/arch/arm/mm/fault-armo.c Tue Dec 22 23:19:28 1998
+++ linux.ac/arch/arm/mm/fault-armo.c Sun Feb 7 23:09:50 1999
@@ -1,11 +1,10 @@
/*
- * linux/arch/arm/mm/fault.c
+ * linux/arch/arm/mm/fault-armo.c
*
* Copyright (C) 1995 Linus Torvalds
- * Modifications for ARM processor (c) 1995, 1996 Russell King
+ * Modifications for ARM processor (c) 1995-1999 Russell King
*/
-#include
#include
#include
#include
@@ -15,8 +14,7 @@
#include
#include
#include
-#include
-#include
+#include
#include
#include
@@ -27,35 +25,32 @@
#define FAULT_CODE_WRITE 0x02
#define FAULT_CODE_USER 0x01
-struct pgtable_cache_struct quicklists;
+#define DO_COW(m) ((m) & (FAULT_CODE_WRITE|FAULT_CODE_FORCECOW))
+#define READ_FAULT(m) (!((m) & FAULT_CODE_WRITE))
-void __bad_pmd(pmd_t *pmd)
+#include "fault-common.c"
+
+static void *alloc_table(int size, int prio)
{
- printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-#ifdef CONFIG_DEBUG_ERRORS
- __backtrace();
-#endif
- set_pmd(pmd, mk_pmd(BAD_PAGETABLE));
+ if (size != 128)
+ printk("invalid table size\n");
+ return (void *)get_page_8k(prio);
}
-void __bad_pmd_kernel(pmd_t *pmd)
+void free_table(void *table)
{
- printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
-#ifdef CONFIG_DEBUG_ERRORS
- __backtrace();
-#endif
- set_pmd(pmd, mk_pmd(BAD_PAGETABLE));
+ free_page_8k((unsigned long)table);
}
pgd_t *get_pgd_slow(void)
{
- pgd_t *pgd = (pgd_t *) kmalloc(PTRS_PER_PGD * BYTES_PER_PTR, GFP_KERNEL);
+ pgd_t *pgd = (pgd_t *)alloc_table(PTRS_PER_PGD * BYTES_PER_PTR, GFP_KERNEL);
pgd_t *init;
-
+
if (pgd) {
init = pgd_offset(&init_mm, 0);
- memzero (pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR);
- memcpy (pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
+ memzero(pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR);
+ memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
(PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR);
}
return pgd;
@@ -65,17 +60,17 @@
{
pte_t *pte;
- pte = (pte_t *) kmalloc (PTRS_PER_PTE * BYTES_PER_PTR, GFP_KERNEL);
+ pte = (pte_t *)alloc_table(PTRS_PER_PTE * BYTES_PER_PTR, GFP_KERNEL);
if (pmd_none(*pmd)) {
if (pte) {
- memzero (pte, PTRS_PER_PTE * BYTES_PER_PTR);
+ memzero(pte, PTRS_PER_PTE * BYTES_PER_PTR);
set_pmd(pmd, mk_pmd(pte));
return pte + offset;
}
set_pmd(pmd, mk_pmd(BAD_PAGETABLE));
return NULL;
}
- kfree (pte);
+ free_table((void *)pte);
if (pmd_bad(*pmd)) {
__bad_pmd(pmd);
return NULL;
@@ -83,126 +78,22 @@
return (pte_t *) pmd_page(*pmd) + offset;
}
-extern void die_if_kernel(char *msg, struct pt_regs *regs, unsigned int err, unsigned int ret);
-
-static void kernel_page_fault (unsigned long addr, int mode, struct pt_regs *regs,
- struct task_struct *tsk, struct mm_struct *mm)
-{
- /*
- * Oops. The kernel tried to access some bad page. We'll have to
- * terminate things with extreme prejudice.
- */
- pgd_t *pgd;
- if (addr < PAGE_SIZE)
- printk (KERN_ALERT "Unable to handle kernel NULL pointer dereference");
- else
- printk (KERN_ALERT "Unable to handle kernel paging request");
- printk (" at virtual address %08lx\n", addr);
- printk (KERN_ALERT "current->tss.memmap = %08lX\n", tsk->tss.memmap);
- pgd = pgd_offset (mm, addr);
- printk (KERN_ALERT "*pgd = %08lx", pgd_val (*pgd));
- if (!pgd_none (*pgd)) {
- pmd_t *pmd;
- pmd = pmd_offset (pgd, addr);
- printk (", *pmd = %08lx", pmd_val (*pmd));
- if (!pmd_none (*pmd))
- printk (", *pte = %08lx", pte_val (*pte_offset (pmd, addr)));
- }
- printk ("\n");
- die_if_kernel ("Oops", regs, mode, SIGKILL);
- do_exit (SIGKILL);
-}
-
-static void
-handle_dataabort (unsigned long addr, int mode, struct pt_regs *regs)
-{
- struct task_struct *tsk;
- struct mm_struct *mm;
- struct vm_area_struct *vma;
- unsigned long fixup;
-
- lock_kernel();
- tsk = current;
- mm = tsk->mm;
-
- down(&mm->mmap_sem);
- vma = find_vma (mm, addr);
- if (!vma)
- goto bad_area;
- if (addr >= vma->vm_start)
- goto good_area;
- if (!(vma->vm_flags & VM_GROWSDOWN) || expand_stack (vma, addr))
- goto bad_area;
-
- /*
- * Ok, we have a good vm_area for this memory access, so
- * we can handle it..
- */
-good_area:
- if (!(mode & FAULT_CODE_WRITE)) { /* write? */
- if (!(vma->vm_flags & (VM_READ|VM_EXEC)))
- goto bad_area;
- } else {
- if (!(vma->vm_flags & VM_WRITE))
- goto bad_area;
- }
- handle_mm_fault (tsk, vma, addr, mode & (FAULT_CODE_WRITE|FAULT_CODE_FORCECOW));
- up(&mm->mmap_sem);
- goto out;
-
- /*
- * Something tried to access memory that isn't in our memory map..
- * Fix it, but check if it's kernel or user first..
- */
-bad_area:
- up(&mm->mmap_sem);
- if (mode & FAULT_CODE_USER) {
-//extern int console_loglevel;
-//cli();
- tsk->tss.error_code = mode;
- tsk->tss.trap_no = 14;
-//console_loglevel = 9;
- printk ("%s: memory violation at pc=0x%08lx, lr=0x%08lx (bad address=0x%08lx, code %d)\n",
- tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode);
-//#ifdef DEBUG
- show_regs (regs);
- c_backtrace (regs->ARM_fp, 0);
-//#endif
- force_sig(SIGSEGV, tsk);
-//while (1);
- goto out;
- }
-
- /* Are we prepared to handle this kernel fault? */
- if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) {
- printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n",
- tsk->comm, regs->ARM_pc, addr, fixup);
- regs->ARM_pc = fixup;
- goto out;
- }
-
-
- kernel_page_fault (addr, mode, regs, tsk, mm);
-out:
- unlock_kernel();
-}
-
/*
* Handle a data abort. Note that we have to handle a range of addresses
* on ARM2/3 for ldm. If both pages are zero-mapped, then we have to force
- * a copy-on-write
+ * a copy-on-write. However, on the second page, we always force COW.
*/
asmlinkage void
-do_DataAbort (unsigned long min_addr, unsigned long max_addr, int mode, struct pt_regs *regs)
+do_DataAbort(unsigned long min_addr, unsigned long max_addr, int mode, struct pt_regs *regs)
{
- handle_dataabort (min_addr, mode, regs);
+ do_page_fault(min_addr, mode, regs);
if ((min_addr ^ max_addr) >> PAGE_SHIFT)
- handle_dataabort (max_addr, mode | FAULT_CODE_FORCECOW, regs);
+ do_page_fault(max_addr, mode | FAULT_CODE_FORCECOW, regs);
}
asmlinkage int
-do_PrefetchAbort (unsigned long addr, int mode, struct pt_regs *regs)
+do_PrefetchAbort(unsigned long addr, struct pt_regs *regs)
{
#if 0
if (the memc mapping for this page exists - can check now...) {
@@ -210,6 +101,6 @@
return 0;
}
#endif
- handle_dataabort (addr, mode, regs);
+ do_page_fault(addr, FAULT_CODE_USER|FAULT_CODE_PREFETCH, regs);
return 1;
}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/mm/fault-armv.c linux.ac/arch/arm/mm/fault-armv.c
--- linux.vanilla/arch/arm/mm/fault-armv.c Tue Dec 22 23:19:28 1998
+++ linux.ac/arch/arm/mm/fault-armv.c Sun Feb 7 23:09:48 1999
@@ -1,10 +1,11 @@
/*
- * linux/arch/arm/mm/fault.c
+ * linux/arch/arm/mm/fault-armv.c
*
* Copyright (C) 1995 Linus Torvalds
- * Modifications for ARM processor (c) 1995, 1996 Russell King
+ * Modifications for ARM processor (c) 1995-1999 Russell King
*/
+#include
#include
#include
#include
@@ -14,42 +15,35 @@
#include
#include
#include
-#include
-#include
+#include
+#include
+#include
#include
#include
#include
+#include
#define FAULT_CODE_READ 0x02
#define FAULT_CODE_USER 0x01
-struct pgtable_cache_struct quicklists;
+#define DO_COW(m) (!((m) & FAULT_CODE_READ))
+#define READ_FAULT(m) ((m) & FAULT_CODE_READ)
-void __bad_pmd(pmd_t *pmd)
-{
- printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
- set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE));
-}
-
-void __bad_pmd_kernel(pmd_t *pmd)
-{
- printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
- set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE));
-}
+#include "fault-common.c"
pgd_t *get_pgd_slow(void)
{
/*
* need to get a 16k page for level 1
*/
- pgd_t *pgd = (pgd_t *) __get_free_pages(GFP_KERNEL,2);
+ pgd_t *pgd = (pgd_t *)__get_free_pages(GFP_KERNEL,2);
pgd_t *init;
-
+
if (pgd) {
init = pgd_offset(&init_mm, 0);
- memzero ((void *)pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR);
- memcpy (pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
+ memzero(pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR);
+ memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
(PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR);
}
return pgd;
@@ -59,17 +53,17 @@
{
pte_t *pte;
- pte = (pte_t *) get_small_page(GFP_KERNEL);
+ pte = (pte_t *)get_page_1k(GFP_KERNEL);
if (pmd_none(*pmd)) {
if (pte) {
- memzero (pte, PTRS_PER_PTE * BYTES_PER_PTR);
+ memzero(pte, PTRS_PER_PTE * BYTES_PER_PTR);
set_pmd(pmd, mk_user_pmd(pte));
return pte + offset;
}
set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE));
return NULL;
}
- free_small_page ((unsigned long) pte);
+ free_page_1k((unsigned long) pte);
if (pmd_bad(*pmd)) {
__bad_pmd(pmd);
return NULL;
@@ -81,17 +75,17 @@
{
pte_t *pte;
- pte = (pte_t *) get_small_page(GFP_KERNEL);
+ pte = (pte_t *) get_page_1k(GFP_KERNEL);
if (pmd_none(*pmd)) {
if (pte) {
- memzero (pte, PTRS_PER_PTE * BYTES_PER_PTR);
+ memzero(pte, PTRS_PER_PTE * BYTES_PER_PTR);
set_pmd(pmd, mk_kernel_pmd(pte));
return pte + offset;
}
set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE));
return NULL;
}
- free_small_page ((unsigned long) pte);
+ free_page_1k((unsigned long) pte);
if (pmd_bad(*pmd)) {
__bad_pmd_kernel(pmd);
return NULL;
@@ -99,10 +93,8 @@
return (pte_t *) pmd_page(*pmd) + offset;
}
-extern void die_if_kernel(char *msg, struct pt_regs *regs, unsigned int err, unsigned int ret);
-
#ifdef DEBUG
-static int sp_valid (unsigned long *sp)
+static int sp_valid(unsigned long *sp)
{
unsigned long addr = (unsigned long) sp;
@@ -114,187 +106,340 @@
}
#endif
-static void kernel_page_fault (unsigned long addr, int mode, struct pt_regs *regs,
- struct task_struct *tsk, struct mm_struct *mm)
+#ifdef CONFIG_ALIGNMENT_TRAP
+/*
+ * 32-bit misaligned trap handler (c) 1998 San Mehat (CCC) -July 1998
+ * /proc/sys/debug/alignment, modified and integrated into
+ * Linux 2.1 by Russell King
+ *
+ * NOTE!!! This is not portable onto the ARM6/ARM7 processors yet. Also,
+ * it seems to give a severe performance impact (1 abort/ms - NW runs at
+ * ARM6 speeds) with GCC 2.7.2.2 - needs checking with a later GCC/EGCS.
+ *
+ * IMHO, I don't think that the trap handler is advantageous on ARM6,7
+ * processors (they'll run like an ARM3). We'll see.
+ */
+#define CODING_BITS(i) (i & 0x0e000000)
+
+#define LDST_I_BIT(i) (i & (1 << 26)) /* Immediate constant */
+#define LDST_P_BIT(i) (i & (1 << 24)) /* Preindex */
+#define LDST_U_BIT(i) (i & (1 << 23)) /* Add offset */
+#define LDST_W_BIT(i) (i & (1 << 21)) /* Writeback */
+#define LDST_L_BIT(i) (i & (1 << 20)) /* Load */
+
+#define LDSTH_I_BIT(i) (i & (1 << 22)) /* half-word immed */
+#define LDM_S_BIT(i) (i & (1 << 22)) /* write CPSR from SPSR */
+
+#define RN_BITS(i) ((i >> 16) & 15) /* Rn */
+#define RD_BITS(i) ((i >> 12) & 15) /* Rd */
+#define RM_BITS(i) (i & 15) /* Rm */
+
+#define REGMASK_BITS(i) (i & 0xffff)
+#define OFFSET_BITS(i) (i & 0x0fff)
+
+#define IS_SHIFT(i) (i & 0x0ff0)
+#define SHIFT_BITS(i) ((i >> 7) & 0x1f)
+#define SHIFT_TYPE(i) (i & 0x60)
+#define SHIFT_LSL 0x00
+#define SHIFT_LSR 0x20
+#define SHIFT_ASR 0x40
+#define SHIFT_RORRRX 0x60
+
+static unsigned long ai_user;
+static unsigned long ai_sys;
+static unsigned long ai_skipped;
+static unsigned long ai_half;
+static unsigned long ai_word;
+static unsigned long ai_multi;
+
+static int proc_alignment_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
{
- /*
- * Oops. The kernel tried to access some bad page. We'll have to
- * terminate things with extreme prejudice.
- */
- pgd_t *pgd;
- if (addr < PAGE_SIZE)
- printk (KERN_ALERT "Unable to handle kernel NULL pointer dereference");
- else
- printk (KERN_ALERT "Unable to handle kernel paging request");
- printk (" at virtual address %08lx\n", addr);
- printk (KERN_ALERT "current->tss.memmap = %08lX\n", tsk->tss.memmap);
- pgd = pgd_offset (mm, addr);
- printk (KERN_ALERT "*pgd = %08lx", pgd_val (*pgd));
- if (!pgd_none (*pgd)) {
- pmd_t *pmd;
- pmd = pmd_offset (pgd, addr);
- printk (", *pmd = %08lx", pmd_val (*pmd));
- if (!pmd_none (*pmd))
- printk (", *pte = %08lx", pte_val (*pte_offset (pmd, addr)));
- }
- printk ("\n");
- die_if_kernel ("Oops", regs, mode, SIGKILL);
- do_exit (SIGKILL);
+ char *p = page;
+ int len;
+
+ p += sprintf(p, "User:\t\t%li\n", ai_user);
+ p += sprintf(p, "System:\t\t%li\n", ai_sys);
+ p += sprintf(p, "Skipped:\t%li\n", ai_skipped);
+ p += sprintf(p, "Half:\t\t%li\n", ai_half);
+ p += sprintf(p, "Word:\t\t%li\n", ai_word);
+ p += sprintf(p, "Multi:\t\t%li\n", ai_multi);
+
+ len = (p - page) - off;
+ if (len < 0)
+ len = 0;
+
+ *eof = (len <= count) ? 1 : 0;
+ *start = page + off;
+
+ return len;
}
-static void page_fault (unsigned long addr, int mode, struct pt_regs *regs)
+/*
+ * This needs to be done after sysctl_init, otherwise sys/
+ * will be overwritten.
+ */
+void __init alignment_init(void)
{
- struct task_struct *tsk;
- struct mm_struct *mm;
- struct vm_area_struct *vma;
- unsigned long fixup;
-
- lock_kernel();
- tsk = current;
- mm = tsk->mm;
-
- down(&mm->mmap_sem);
- vma = find_vma (mm, addr);
- if (!vma)
- goto bad_area;
- if (vma->vm_start <= addr)
- goto good_area;
- if (!(vma->vm_flags & VM_GROWSDOWN) || expand_stack (vma, addr))
- goto bad_area;
+ struct proc_dir_entry *e;
- /*
- * Ok, we have a good vm_area for this memory access, so
- * we can handle it..
- */
-good_area:
- if (mode & FAULT_CODE_READ) { /* read? */
- if (!(vma->vm_flags & (VM_READ|VM_EXEC)))
- goto bad_area;
- } else {
- if (!(vma->vm_flags & VM_WRITE))
- goto bad_area;
- }
- handle_mm_fault (tsk, vma, addr & PAGE_MASK, !(mode & FAULT_CODE_READ));
- up(&mm->mmap_sem);
- goto out;
+ e = create_proc_entry("sys/debug/alignment", S_IFREG | S_IRUGO, NULL);
- /*
- * Something tried to access memory that isn't in our memory map..
- * Fix it, but check if it's kernel or user first..
- */
-bad_area:
- up(&mm->mmap_sem);
- if (mode & FAULT_CODE_USER) {
- tsk->tss.error_code = mode;
- tsk->tss.trap_no = 14;
- printk ("%s: memory violation at pc=0x%08lx, lr=0x%08lx (bad address=0x%08lx, code %d)\n",
- tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode);
-#ifdef DEBUG
- {
- unsigned int i, j;
- unsigned long *sp = (unsigned long *) (regs->ARM_sp - 128);
- for (j = 0; j < 20 && sp_valid (sp); j++) {
- printk ("%p: ", sp);
- for (i = 0; i < 8 && sp_valid (sp); i += 1, sp++)
- printk ("%08lx ", *sp);
- printk ("\n");
+ if (e)
+ e->read_proc = proc_alignment_read;
+}
+
+static void
+do_alignment_exception(struct pt_regs *regs)
+{
+ unsigned int instr, rd, rn, correction, nr_regs, regbits;
+ unsigned long eaddr;
+ union { unsigned long un; signed long sn; } offset;
+
+ if (user_mode(regs)) {
+ set_cr(cr_no_alignment);
+ ai_user += 1;
+ return;
+ }
+
+ ai_sys += 1;
+
+ instr = *(unsigned long *)instruction_pointer(regs);
+ correction = 4; /* sometimes 8 on ARMv3 */
+ regs->ARM_pc += correction + 4;
+
+ rd = RD_BITS(instr);
+ rn = RN_BITS(instr);
+ eaddr = regs->uregs[rn];
+
+ switch(CODING_BITS(instr)) {
+ case 0x00000000:
+ if ((instr & 0x0ff00ff0) == 0x01000090) {
+ ai_skipped += 1;
+ printk(KERN_ERR "Unaligned trap: not handling swp instruction\n");
+ break;
+ }
+
+ if (((instr & 0x0e000090) == 0x00000090) && (instr & 0x60) != 0) {
+ ai_half += 1;
+ if (LDSTH_I_BIT(instr))
+ offset.un = (instr & 0xf00) >> 4 | (instr & 15);
+ else
+ offset.un = regs->uregs[RM_BITS(instr)];
+
+ if (LDST_P_BIT(instr)) {
+ if (LDST_U_BIT(instr))
+ eaddr += offset.un;
+ else
+ eaddr -= offset.un;
}
+
+ if (LDST_L_BIT(instr))
+ regs->uregs[rd] = get_unaligned((unsigned short *)eaddr);
+ else
+ put_unaligned(regs->uregs[rd], (unsigned short *)eaddr);
+
+ /* signed half-word? */
+ if (instr & 0x40)
+ regs->uregs[rd] = (long)((short) regs->uregs[rd]);
+
+ if (!LDST_P_BIT(instr)) {
+ if (LDST_U_BIT(instr))
+ eaddr += offset.un;
+ else
+ eaddr -= offset.un;
+ regs->uregs[rn] = eaddr;
+ } else if (LDST_W_BIT(instr))
+ regs->uregs[rn] = eaddr;
+ break;
}
- show_regs (regs);
- c_backtrace (regs->ARM_fp, regs->ARM_cpsr);
-#endif
- force_sig(SIGSEGV, tsk);
- goto out;
- }
- /* Are we prepared to handle this kernel fault? */
- if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) {
- printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n",
- tsk->comm, regs->ARM_pc, addr, fixup);
- regs->ARM_pc = fixup;
- goto out;
+ default:
+ ai_skipped += 1;
+ panic("Alignment trap: not handling instruction %08X at %08lX",
+ instr, regs->ARM_pc - correction - 4);
+ break;
+
+ case 0x04000000:
+ offset.un = OFFSET_BITS(instr);
+ goto ldr_str;
+
+ case 0x06000000:
+ offset.un = regs->uregs[RM_BITS(instr)];
+
+ if (IS_SHIFT(instr)) {
+ unsigned int shiftval = SHIFT_BITS(instr);
+
+ switch(SHIFT_TYPE(instr)) {
+ case SHIFT_LSL:
+ offset.un <<= shiftval;
+ break;
+
+ case SHIFT_LSR:
+ offset.un >>= shiftval;
+ break;
+
+ case SHIFT_ASR:
+ offset.sn >>= shiftval;
+ break;
+
+ case SHIFT_RORRRX:
+ if (shiftval == 0) {
+ offset.un >>= 1;
+ if (regs->ARM_cpsr & CC_C_BIT)
+ offset.un |= 1 << 31;
+ } else
+ offset.un = offset.un >> shiftval |
+ offset.un << (32 - shiftval);
+ break;
+ }
+ }
+
+ ldr_str:
+ ai_word += 1;
+ if (LDST_P_BIT(instr)) {
+ if (LDST_U_BIT(instr))
+ eaddr += offset.un;
+ else
+ eaddr -= offset.un;
+ } else {
+ if (LDST_W_BIT(instr))
+ printk(KERN_ERR "Not handling ldrt/strt correctly\n");
+ }
+
+ if (LDST_L_BIT(instr)) {
+ regs->uregs[rd] = get_unaligned((unsigned long *)eaddr);
+ if (rd == 15)
+ correction = 0;
+ } else
+ put_unaligned(regs->uregs[rd], (unsigned long *)eaddr);
+
+ if (!LDST_P_BIT(instr)) {
+ if (LDST_U_BIT(instr))
+ eaddr += offset.un;
+ else
+ eaddr -= offset.un;
+
+ regs->uregs[rn] = eaddr;
+ } else if (LDST_W_BIT(instr))
+ regs->uregs[rn] = eaddr;
+ break;
+
+ case 0x08000000:
+ if (LDM_S_BIT(instr))
+ panic("Alignment trap: not handling LDM with s-bit\n");
+ ai_multi += 1;
+
+ for (regbits = REGMASK_BITS(instr), nr_regs = 0; regbits; regbits >>= 1)
+ nr_regs += 4;
+
+ if (!LDST_U_BIT(instr))
+ eaddr -= nr_regs;
+
+ if ((LDST_U_BIT(instr) == 0 && LDST_P_BIT(instr) == 0) ||
+ (LDST_U_BIT(instr) && LDST_P_BIT(instr)))
+ eaddr += 4;
+
+ for (regbits = REGMASK_BITS(instr), rd = 0; regbits; regbits >>= 1, rd += 1)
+ if (regbits & 1) {
+ if (LDST_L_BIT(instr)) {
+ regs->uregs[rd] = get_unaligned((unsigned long *)eaddr);
+ if (rd == 15)
+ correction = 0;
+ } else
+ put_unaligned(regs->uregs[rd], (unsigned long *)eaddr);
+ eaddr += 4;
+ }
+
+ if (LDST_W_BIT(instr)) {
+ if (LDST_P_BIT(instr) && !LDST_U_BIT(instr))
+ eaddr -= nr_regs;
+ else if (LDST_P_BIT(instr))
+ eaddr -= 4;
+ else if (!LDST_U_BIT(instr))
+ eaddr -= 4 + nr_regs;
+ regs->uregs[rn] = eaddr;
+ }
+ break;
}
- kernel_page_fault (addr, mode, regs, tsk, mm);
-out:
- unlock_kernel();
+ regs->ARM_pc -= correction;
}
-/*
- * Handle a data abort. Note that we have to handle a range of addresses
- * on ARM2/3 for ldm. If both pages are zero-mapped, then we have to force
- * a copy-on-write
- */
+#endif
+
asmlinkage void
-do_DataAbort (unsigned long addr, int fsr, int error_code, struct pt_regs *regs)
+do_DataAbort(unsigned long addr, int fsr, int error_code, struct pt_regs *regs)
{
if (user_mode(regs))
error_code |= FAULT_CODE_USER;
+
#define DIE(signr,nam)\
force_sig(signr, current);\
die_if_kernel(nam, regs, fsr, signr);\
- break;
+ break
switch (fsr & 15) {
case 2:
- DIE(SIGKILL, "Terminal exception")
+ DIE(SIGKILL, "Terminal exception");
case 0:
- DIE(SIGSEGV, "Vector exception")
+ DIE(SIGSEGV, "Vector exception");
case 1:
case 3:
- DIE(SIGBUS, "Alignment exception")
+#ifdef CONFIG_ALIGNMENT_TRAP
+ do_alignment_exception(regs);
+#else
+ /* this should never happen */
+ DIE(SIGBUS, "Alignment exception");
+#endif
+ break;
+
case 12:
case 14:
- DIE(SIGBUS, "External abort on translation")
+ DIE(SIGBUS, "External abort on translation");
case 9:
case 11:
- DIE(SIGSEGV, "Domain fault")
+ DIE(SIGSEGV, "Domain fault");
case 13:/* permission fault on section */
+#ifdef CONFIG_DEBUG_USER
+ printk("%s: permission fault on section, address=0x%08lx, code %d\n",
+ current->comm, addr, error_code);
#ifdef DEBUG
{
unsigned int i, j;
unsigned long *sp;
- printk ("%s: section permission fault (bad address=0x%08lx, code %d)\n",
- current->comm, addr, error_code);
sp = (unsigned long *) (regs->ARM_sp - 128);
- for (j = 0; j < 20 && sp_valid (sp); j++) {
- printk ("%p: ", sp);
- for (i = 0; i < 8 && sp_valid (sp); i += 1, sp++)
- printk ("%08lx ", *sp);
- printk ("\n");
+ for (j = 0; j < 20 && sp_valid(sp); j++) {
+ printk("%p: ", sp);
+ for (i = 0; i < 8 && sp_valid(sp); i += 1, sp++)
+ printk("%08lx ", *sp);
+ printk("\n");
}
- show_regs (regs);
+ show_regs(regs);
c_backtrace(regs->ARM_fp, regs->ARM_cpsr);
}
#endif
- DIE(SIGSEGV, "Permission fault")
+#endif
+ DIE(SIGSEGV, "Permission fault");
case 15:/* permission fault on page */
case 5: /* page-table entry descriptor fault */
case 7: /* first-level descriptor fault */
- page_fault (addr, error_code, regs);
+ do_page_fault(addr, error_code, regs);
break;
case 4:
case 6:
- DIE(SIGBUS, "External abort on linefetch")
+ DIE(SIGBUS, "External abort on linefetch");
case 8:
case 10:
- DIE(SIGBUS, "External abort on non-linefetch")
+ DIE(SIGBUS, "External abort on non-linefetch");
}
}
asmlinkage int
-do_PrefetchAbort (unsigned long addr, struct pt_regs *regs)
+do_PrefetchAbort(unsigned long addr, struct pt_regs *regs)
{
-#if 0
- /* does this still apply ? */
- if (the memc mapping for this page exists - can check now...) {
- printk ("Page in, but got abort (undefined instruction?)\n");
- return 0;
- }
-#endif
- page_fault (addr, FAULT_CODE_USER|FAULT_CODE_READ, regs);
+ do_page_fault(addr, FAULT_CODE_USER|FAULT_CODE_READ, regs);
return 1;
}
-
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/mm/fault-common.c linux.ac/arch/arm/mm/fault-common.c
--- linux.vanilla/arch/arm/mm/fault-common.c Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/mm/fault-common.c Tue Feb 9 22:25:06 1999
@@ -0,0 +1,167 @@
+/*
+ * linux/arch/arm/mm/fault-common.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ * Modifications for ARM processor (c) 1995-1999 Russell King
+ */
+#include
+
+extern void die_if_kernel(char *msg, struct pt_regs *regs, unsigned int err, unsigned int ret);
+
+void __bad_pmd(pmd_t *pmd)
+{
+ printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+#ifdef CONFIG_DEBUG_ERRORS
+ __backtrace();
+#endif
+ set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE));
+}
+
+void __bad_pmd_kernel(pmd_t *pmd)
+{
+ printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
+#ifdef CONFIG_DEBUG_ERRORS
+ __backtrace();
+#endif
+ set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE));
+}
+
+static void
+kernel_page_fault(unsigned long addr, int mode, struct pt_regs *regs,
+ struct task_struct *tsk, struct mm_struct *mm)
+{
+ char *reason;
+ /*
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ */
+ pgd_t *pgd;
+
+ if (addr < PAGE_SIZE)
+ reason = "NULL pointer dereference";
+ else
+ reason = "paging request";
+
+ printk(KERN_ALERT "Unable to handle kernel %s at virtual address %08lx\n",
+ reason, addr);
+ printk(KERN_ALERT "current->tss.memmap = %08lX\n", tsk->tss.memmap);
+ pgd = pgd_offset(mm, addr);
+ printk(KERN_ALERT "*pgd = %08lx", pgd_val(*pgd));
+
+ if (!pgd_none(*pgd)) {
+ pmd_t *pmd;
+ pmd = pmd_offset(pgd, addr);
+ printk(", *pmd = %08lx", pmd_val(*pmd));
+ if (!pmd_none(*pmd))
+ printk(", *pte = %08lx", pte_val(*pte_offset(pmd, addr)));
+ }
+
+ printk("\n");
+ die_if_kernel("Oops", regs, mode, SIGKILL);
+ do_exit(SIGKILL);
+}
+
+static void do_page_fault(unsigned long addr, int mode, struct pt_regs *regs)
+{
+ struct task_struct *tsk;
+ struct mm_struct *mm;
+ struct vm_area_struct *vma;
+ unsigned long fixup;
+
+ tsk = current;
+ mm = tsk->mm;
+
+ /*
+ * If we're in an interrupt or have no user
+ * context, we must not take the fault..
+ */
+ if (in_interrupt() || mm == &init_mm)
+ goto no_context;
+
+ down(&mm->mmap_sem);
+ vma = find_vma(mm, addr);
+ if (!vma)
+ goto bad_area;
+ if (vma->vm_start <= addr)
+ goto good_area;
+ if (!(vma->vm_flags & VM_GROWSDOWN) || expand_stack(vma, addr))
+ goto bad_area;
+
+ /*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
+ */
+good_area:
+ if (READ_FAULT(mode)) { /* read? */
+ if (!(vma->vm_flags & (VM_READ|VM_EXEC)))
+ goto bad_area;
+ } else {
+ if (!(vma->vm_flags & VM_WRITE))
+ goto bad_area;
+ }
+
+ /*
+ * If for any reason at all we couldn't handle the fault,
+ * make sure we exit gracefully rather than endlessly redo
+ * the fault.
+ */
+ if (!handle_mm_fault(tsk, vma, addr & PAGE_MASK, DO_COW(mode)))
+ goto do_sigbus;
+
+ up(&mm->mmap_sem);
+ return;
+
+ /*
+ * Something tried to access memory that isn't in our memory map..
+ * Fix it, but check if it's kernel or user first..
+ */
+bad_area:
+ up(&mm->mmap_sem);
+
+ /* User mode accesses just cause a SIGSEGV */
+ if (mode & FAULT_CODE_USER) {
+ tsk->tss.error_code = mode;
+ tsk->tss.trap_no = 14;
+#ifdef CONFIG_DEBUG_USER
+ printk("%s: memory violation at pc=0x%08lx, lr=0x%08lx (bad address=0x%08lx, code %d)\n",
+ tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode);
+#endif
+ force_sig(SIGSEGV, tsk);
+ return;
+ }
+
+no_context:
+ /* Are we prepared to handle this kernel fault? */
+ if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) {
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n",
+ tsk->comm, regs->ARM_pc, addr, fixup);
+#endif
+ regs->ARM_pc = fixup;
+ return;
+ }
+
+ kernel_page_fault(addr, mode, regs, tsk, mm);
+ return;
+
+do_sigbus:
+ /*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+ up(&mm->mmap_sem);
+
+ /*
+ * Send a sigbus, regardless of whether we were in kernel
+ * or user mode.
+ */
+ tsk->tss.error_code = mode;
+ tsk->tss.trap_no = 14;
+ force_sig(SIGBUS, tsk);
+
+ /* Kernel mode? Handle exceptions or die */
+ if (!(mode & FAULT_CODE_USER))
+ goto no_context;
+}
+
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/mm/init.c linux.ac/arch/arm/mm/init.c
--- linux.vanilla/arch/arm/mm/init.c Tue Dec 22 23:19:28 1998
+++ linux.ac/arch/arm/mm/init.c Sun Feb 7 19:37:58 1999
@@ -29,6 +29,9 @@
#include
pgd_t swapper_pg_dir[PTRS_PER_PGD];
+#ifndef CONFIG_NO_PGT_CACHE
+struct pgtable_cache_struct quicklists;
+#endif
extern char _etext, _stext, _edata, __bss_start, _end;
extern char __init_begin, __init_end;
@@ -36,6 +39,7 @@
int do_check_pgt_cache(int low, int high)
{
int freed = 0;
+#ifndef CONFIG_NO_PGT_CACHE
if(pgtable_cache_size > high) {
do {
if(pgd_quicklist)
@@ -46,6 +50,7 @@
free_pte_slow(get_pte_fast()), freed++;
} while(pgtable_cache_size > low);
}
+#endif
return freed;
}
@@ -137,6 +142,9 @@
flush_tlb_all();
update_memc_all();
+ end_mem &= PAGE_MASK;
+ high_memory = (void *)end_mem;
+
return free_area_init(start_mem, end_mem);
}
@@ -161,19 +169,18 @@
/* mark usable pages in the mem_map[] */
mark_usable_memory_areas(&start_mem, end_mem);
+#define BETWEEN(w,min,max) ((w) >= (unsigned long)(min) && \
+ (w) < (unsigned long)(max))
+
for (tmp = PAGE_OFFSET; tmp < end_mem ; tmp += PAGE_SIZE) {
if (PageReserved(mem_map+MAP_NR(tmp))) {
- if (tmp >= KERNTOPHYS(_stext) &&
- tmp < KERNTOPHYS(_edata)) {
- if (tmp < KERNTOPHYS(_etext))
- codepages++;
- else
- datapages++;
- } else if (tmp >= KERNTOPHYS(__init_begin)
- && tmp < KERNTOPHYS(__init_end))
+ if (BETWEEN(tmp, &__init_begin, &__init_end))
initpages++;
- else if (tmp >= KERNTOPHYS(__bss_start)
- && tmp < (unsigned long) start_mem)
+ else if (BETWEEN(tmp, &_stext, &_etext))
+ codepages++;
+ else if (BETWEEN(tmp, &_etext, &_edata))
+ datapages++;
+ else if (BETWEEN(tmp, &__bss_start, start_mem))
datapages++;
else
reservedpages++;
@@ -181,13 +188,16 @@
}
atomic_set(&mem_map[MAP_NR(tmp)].count, 1);
#ifdef CONFIG_BLK_DEV_INITRD
- if (!initrd_start || (tmp < initrd_start || tmp >= initrd_end))
+ if (!initrd_start || !BETWEEN(tmp, initrd_start, initrd_end))
#endif
free_page(tmp);
}
- printk ("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n",
+
+#undef BETWEEN
+
+ printk ("Memory: %luk/%luM available (%dk code, %dk reserved, %dk data, %dk init)\n",
(unsigned long) nr_free_pages << (PAGE_SHIFT-10),
- max_mapnr << (PAGE_SHIFT-10),
+ max_mapnr >> (20 - PAGE_SHIFT),
codepages << (PAGE_SHIFT-10),
reservedpages << (PAGE_SHIFT-10),
datapages << (PAGE_SHIFT-10),
@@ -203,17 +213,45 @@
#endif
}
-void free_initmem (void)
+static void free_area(unsigned long addr, unsigned long end, char *s)
{
- unsigned long addr;
+ unsigned int size = (end - addr) >> 10;
- addr = (unsigned long)(&__init_begin);
- for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
+ for (; addr < end; addr += PAGE_SIZE) {
mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
atomic_set(&mem_map[MAP_NR(addr)].count, 1);
free_page(addr);
}
- printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
+
+ if (size)
+ printk(" %dk %s", size, s);
+}
+
+void free_initmem (void)
+{
+ printk("Freeing unused kernel memory:");
+
+ free_area((unsigned long)(&__init_begin),
+ (unsigned long)(&__init_end),
+ "init");
+
+#ifdef CONFIG_FOOTBRIDGE
+ {
+ extern int __netwinder_begin, __netwinder_end, __ebsa285_begin, __ebsa285_end;
+
+ if (!machine_is_netwinder())
+ free_area((unsigned long)(&__netwinder_begin),
+ (unsigned long)(&__netwinder_end),
+ "netwinder");
+
+ if (!machine_is_ebsa285() && !machine_is_cats())
+ free_area((unsigned long)(&__ebsa285_begin),
+ (unsigned long)(&__ebsa285_end),
+ "ebsa285/cats");
+ }
+#endif
+
+ printk("\n");
}
void si_meminfo(struct sysinfo *val)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/mm/ioremap.c linux.ac/arch/arm/mm/ioremap.c
--- linux.vanilla/arch/arm/mm/ioremap.c Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/mm/ioremap.c Wed Jan 6 23:34:08 1999
@@ -0,0 +1,153 @@
+/*
+ * arch/arm/mm/ioremap.c
+ *
+ * Re-map IO memory to kernel address space so that we can access it.
+ *
+ * (C) Copyright 1995 1996 Linus Torvalds
+ *
+ * Hacked for ARM by Phil Blundell
+ * Hacked to allow all architectures to build, and various cleanups
+ * by Russell King
+ */
+
+/*
+ * This allows a driver to remap an arbitrary region of bus memory into
+ * virtual space. One should *only* use readl, writel, memcpy_toio and
+ * so on with such remapped areas.
+ *
+ * Because the ARM only has a 32-bit address space we can't address the
+ * whole of the (physical) PCI space at once. PCI huge-mode addressing
+ * allows us to circumvent this restriction by splitting PCI space into
+ * two 2GB chunks and mapping only one at a time into processor memory.
+ * We use MMU protection domains to trap any attempt to access the bank
+ * that is not currently mapped. (This isn't fully implemented yet.)
+ *
+ * DC21285 currently has a bug in that the PCI address extension
+ * register affects the address of any writes waiting in the outbound
+ * FIFO. Unfortunately, it is not possible to tell the DC21285 to
+ * flush this - flushing the area causes the bus to lock.
+ */
+
+#include
+#include
+
+/*
+ * Only include this if we have valid_ioaddr() is defined
+ */
+#ifdef valid_ioaddr
+
+static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
+ unsigned long phys_addr, pgprot_t pgprot)
+{
+ unsigned long end;
+
+ address &= ~PMD_MASK;
+ end = address + size;
+ if (end > PMD_SIZE)
+ end = PMD_SIZE;
+ do {
+ if (!pte_none(*pte))
+ printk("remap_area_pte: page already exists\n");
+ set_pte(pte, mk_pte_phys(phys_addr, pgprot));
+ address += PAGE_SIZE;
+ phys_addr += PAGE_SIZE;
+ pte++;
+ } while (address < end);
+}
+
+static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
+ unsigned long phys_addr, unsigned long flags)
+{
+ unsigned long end;
+ pgprot_t pgprot;
+
+ address &= ~PGDIR_MASK;
+ end = address + size;
+
+ if (end > PGDIR_SIZE)
+ end = PGDIR_SIZE;
+
+ phys_addr -= address;
+ pgprot = __pgprot(PTE_TYPE_SMALL | _PTE_WRITE | flags);
+ do {
+ pte_t * pte = pte_alloc_kernel(pmd, address);
+ if (!pte)
+ return -ENOMEM;
+ remap_area_pte(pte, address, end - address, address + phys_addr, pgprot);
+ address = (address + PMD_SIZE) & PMD_MASK;
+ pmd++;
+ } while (address < end);
+ return 0;
+}
+
+static int remap_area_pages(unsigned long address, unsigned long phys_addr,
+ unsigned long size, unsigned long flags)
+{
+ pgd_t * dir;
+ unsigned long end = address + size;
+
+ phys_addr -= address;
+ dir = pgd_offset(&init_mm, address);
+ flush_cache_all();
+ while (address < end) {
+ pmd_t *pmd = pmd_alloc_kernel(dir, address);
+ if (!pmd)
+ return -ENOMEM;
+ if (remap_area_pmd(pmd, address, end - address,
+ phys_addr + address, flags))
+ return -ENOMEM;
+ set_pgdir(address, *dir);
+ address = (address + PGDIR_SIZE) & PGDIR_MASK;
+ dir++;
+ }
+ flush_tlb_all();
+ return 0;
+}
+
+/*
+ * Remap an arbitrary physical address space into the kernel virtual
+ * address space. Needed when the kernel wants to access high addresses
+ * directly.
+ *
+ * NOTE! We need to allow non-page-aligned mappings too: we will obviously
+ * have to convert them into an offset in a page-aligned mapping, but the
+ * caller shouldn't need to know that small detail.
+ */
+void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
+{
+ void * addr;
+ struct vm_struct * area;
+ unsigned long offset;
+
+ /*
+ * Mappings have to be page-aligned
+ */
+ offset = phys_addr & ~PAGE_MASK;
+ size = PAGE_ALIGN(size + offset);
+
+ /*
+ * Don't allow mappings that wrap..
+ */
+ if (!size || size > phys_addr + size)
+ return NULL;
+
+ /*
+ * Ok, go for it..
+ */
+ area = get_vm_area(size);
+ if (!area)
+ return NULL;
+ addr = area->addr;
+ if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) {
+ vfree(addr);
+ return NULL;
+ }
+ return (void *) (offset + (char *)addr);
+}
+
+void iounmap(void *addr)
+{
+ return vfree((void *) (PAGE_MASK & (unsigned long) addr));
+}
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/mm/mm-arc.c linux.ac/arch/arm/mm/mm-arc.c
--- linux.vanilla/arch/arm/mm/mm-arc.c Sun Nov 8 15:08:45 1998
+++ linux.ac/arch/arm/mm/mm-arc.c Thu Jan 1 01:00:00 1970
@@ -1,82 +0,0 @@
-/*
- * arch/arm/mm/mm-arc.c
- *
- * Extra MM routines for the Archimedes architecture
- *
- * Copyright (C) 1998 Russell King
- */
-#include
-#include
-#include
-
-unsigned long phys_screen_end;
-
-/*
- * This routine needs more work to make it dynamically release/allocate mem!
- */
-__initfunc(unsigned long map_screen_mem(unsigned long log_start, unsigned long kmem, int update))
-{
- static int updated = 0;
-
- if (updated)
- return 0;
-
- updated = update;
-
- if (update) {
- unsigned long address = log_start, offset;
- pgd_t *pgdp;
-
- kmem = (kmem + 3) & ~3;
-
- pgdp = pgd_offset (&init_mm, address); /* +31 */
- offset = SCREEN_START;
- while (address < SCREEN1_END) {
- unsigned long addr_pmd, end_pmd;
- pmd_t *pmdp;
-
- /* if (pgd_none (*pgdp)) alloc pmd */
- pmdp = pmd_offset (pgdp, address); /* +0 */
- addr_pmd = address & ~PGDIR_MASK; /* 088000 */
- end_pmd = addr_pmd + SCREEN1_END - address; /* 100000 */
- if (end_pmd > PGDIR_SIZE)
- end_pmd = PGDIR_SIZE;
-
- do {
- unsigned long addr_pte, end_pte;
- pte_t *ptep;
-
- if (pmd_none (*pmdp)) {
- pte_t *new_pte = (pte_t *)kmem;
- kmem += PTRS_PER_PTE * BYTES_PER_PTR;
- memzero (new_pte, PTRS_PER_PTE * BYTES_PER_PTR);
- set_pmd (pmdp, mk_pmd(new_pte));
- }
-
- ptep = pte_offset (pmdp, addr_pmd); /* +11 */
- addr_pte = addr_pmd & ~PMD_MASK; /* 088000 */
- end_pte = addr_pte + end_pmd - addr_pmd; /* 100000 */
- if (end_pte > PMD_SIZE)
- end_pte = PMD_SIZE;
-
- do {
- set_pte (ptep, mk_pte(offset, PAGE_KERNEL));
- addr_pte += PAGE_SIZE;
- offset += PAGE_SIZE;
- ptep++;
- } while (addr_pte < end_pte);
-
- pmdp++;
- addr_pmd = (addr_pmd + PMD_SIZE) & PMD_MASK;
- } while (addr_pmd < end_pmd);
-
- address = (address + PGDIR_SIZE) & PGDIR_MASK;
- pgdp ++;
- }
-
- phys_screen_end = offset;
- flush_tlb_all ();
- update_memc_all ();
- }
- return kmem;
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/mm/mm-ebsa285.c linux.ac/arch/arm/mm/mm-ebsa285.c
--- linux.vanilla/arch/arm/mm/mm-ebsa285.c Tue Dec 22 23:19:28 1998
+++ linux.ac/arch/arm/mm/mm-ebsa285.c Tue Jan 26 22:36:20 1999
@@ -16,24 +16,23 @@
#include
/*
- * This is to allow us to fiddle with the EEPROM
- * This entry will go away in time, once the fmu
- * can mmap() the flash.
+ * The first entry allows us to fiddle with the EEPROM from user-space.
+ * This entry will go away in time, once the fmu32 can mmap() the
+ * flash. It can't at the moment.
*
- * These ones are so that we can fiddle
- * with the various cards (eg VGA)
- * until we're happy with them...
+ * If you want to fiddle with PCI VGA cards from user space, then
+ * change the '0, 1 }' for the PCI MEM and PCI IO to '1, 1 }'
+ * You can then access the PCI bus at 0xe0000000 and 0xffe00000.
*/
#define MAPPING \
- { 0xd8000000, DC21285_FLASH, 0x00400000, DOMAIN_USER, 1, 1 }, /* EEPROM */ \
- { 0xdc000000, 0x7c000000, 0x00100000, DOMAIN_USER, 1, 1 }, /* VGA */ \
- { 0xe0000000, DC21285_PCI_MEM, 0x18000000, DOMAIN_USER, 1, 1 }, /* VGA */ \
+ { 0xd8000000, DC21285_FLASH, 0x00400000, DOMAIN_IO , 0, 1 }, /* EEPROM */ \
+ { 0xe0000000, DC21285_PCI_MEM, 0x18000000, DOMAIN_IO , 0, 1 }, /* PCI memory */ \
{ 0xf8000000, DC21285_PCI_TYPE_0_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 0 Config */ \
{ 0xf9000000, DC21285_PCI_TYPE_1_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 1 Config */ \
{ PCI_IACK, DC21285_PCI_IACK, 0x01000000, DOMAIN_IO , 0, 1 }, /* PCI IACK */ \
{ 0xfd000000, DC21285_OUTBOUND_WRITE_FLUSH, 0x01000000, DOMAIN_IO , 0, 1 }, /* Out wrflsh */ \
- { 0xfe000000, DC21285_ARMCSR_BASE, 0x01000000, DOMAIN_IO , 0, 1 }, /* CSR */ \
- { 0xffe00000, DC21285_PCI_IO, 0x00100000, DOMAIN_IO , 0, 1 }, /* PCI I/O */ \
+ { ARMCSR_BASE,DC21285_ARMCSR_BASE, 0x01000000, DOMAIN_IO , 0, 1 }, /* CSR */ \
+ { PCIO_BASE, DC21285_PCI_IO, 0x00100000, DOMAIN_IO , 0, 1 }, /* PCI I/O */ \
{ 0xfff00000, 0x40000000, 0x00100000, DOMAIN_IO , 0, 1 }, /* X-Bus */
#include "mm-armv.c"
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/mm/mm-vnc.c linux.ac/arch/arm/mm/mm-vnc.c
--- linux.vanilla/arch/arm/mm/mm-vnc.c Tue Dec 22 23:19:28 1998
+++ linux.ac/arch/arm/mm/mm-vnc.c Thu Jan 1 01:00:00 1970
@@ -1,31 +0,0 @@
-/*
- * arch/arm/mm/mm-vnc.c
- *
- * Extra MM routines for the Corel VNC architecture
- *
- * Copyright (C) 1998 Russell King
- */
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-
-/* Table describing the MMU translation mapping
- * mainly used to set up the I/O mappings.
- */
-#define MAPPING \
- { 0xd0000000, DC21285_FLASH, 0x00800000, DOMAIN_IO , 0, 1 }, /* Flash */ \
- { 0xe0000000, DC21285_PCI_MEM, 0x18000000, DOMAIN_IO , 0, 1 }, /* PCI Mem */ \
- { 0xf8000000, DC21285_PCI_TYPE_0_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 0 Config */ \
- { 0xf9000000, DC21285_PCI_TYPE_1_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 1 Config */ \
- { PCI_IACK, DC21285_PCI_IACK, 0x01000000, DOMAIN_IO , 0, 1 }, /* PCI IACK */ \
- { 0xfd000000, DC21285_OUTBOUND_WRITE_FLUSH, 0x01000000, DOMAIN_IO , 0, 1 }, /* Out wrflsh */ \
- { 0xfe000000, DC21285_ARMCSR_BASE, 0x01000000, DOMAIN_IO , 0, 1 }, /* CSR */ \
- { 0xffe00000, DC21285_PCI_IO, 0x00100000, DOMAIN_IO , 0, 1 }, /* PCI I/O */ \
-
-#include "mm-armv.c"
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/mm/proc-arm2,3.S linux.ac/arch/arm/mm/proc-arm2,3.S
--- linux.vanilla/arch/arm/mm/proc-arm2,3.S Sun Nov 8 15:08:45 1998
+++ linux.ac/arch/arm/mm/proc-arm2,3.S Tue Feb 2 20:23:41 1999
@@ -193,7 +193,7 @@
movs pc, lr
_arm2_3_check_bugs:
- movs pc, lr
+ bics pc, lr, #0x04000000 @ Clear FIQ disable bit
/*
* Processor specific - ARM2
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/mm/proc-sa110.S linux.ac/arch/arm/mm/proc-sa110.S
--- linux.vanilla/arch/arm/mm/proc-sa110.S Tue Dec 22 23:19:28 1998
+++ linux.ac/arch/arm/mm/proc-sa110.S Sun Feb 28 12:19:05 1999
@@ -8,6 +8,7 @@
*/
#include
#include
+#include
#include "../lib/constants.h"
/* This is the maximum size of an area which will be flushed. If the area
@@ -21,7 +22,6 @@
/*
* Function: sa110_flush_cache_all (void)
- *
* Purpose : Flush all cache lines
*/
.align 5
@@ -33,7 +33,7 @@
ands r1, r1, #1
eor r1, r1, #1
str r1, [r3]
- ldr ip, =0xdf000000
+ ldr ip, =FLUSH_BASE
addne ip, ip, #32768
add r1, ip, #16384 @ only necessary for 16k
1: ldr r3, [ip], #32
@@ -47,11 +47,9 @@
/*
* Function: sa110_flush_cache_area (unsigned long address, int end, int flags)
- *
* Params : address Area start address
* : end Area end address
* : flags b0 = I cache as well
- *
* Purpose : clean & flush all cache lines associated with this area of memory
*/
.align 5
@@ -74,10 +72,8 @@
/*
* Function: sa110_cache_wback_area(unsigned long address, unsigned long end)
- *
* Params : address Area start address
* : end Area end address
- *
* Purpose : ensure all dirty cachelines in the specified area have been
* written out to memory (for DMA)
*/
@@ -99,13 +95,10 @@
/*
* Function: sa110_cache_purge_area(unsigned long address, unsigned long end)
- *
* Params : address Area start address
* : end Area end address
- *
* Purpose : throw away all D-cached data in specified region without
- * an obligation to write it ack.
- *
+ * an obligation to write it back.
* Note : Must clean the D-cached entries around the boundaries if the
* start and/or end address are not cache aligned.
*/
@@ -124,9 +117,7 @@
/*
* Function: sa110_flush_cache_entry (unsigned long address)
- *
* Params : address Address of cache line to flush
- *
* Purpose : clean & flush an entry
*/
.align 5
@@ -139,9 +130,7 @@
/*
* Function: sa110_flush_cache_pte (unsigned long address)
- *
* Params : address Address of cache line to clean
- *
* Purpose : Ensure that physical memory reflects cache at this location
* for page table purposes.
*/
@@ -151,11 +140,9 @@
/*
* Function: sa110_flush_ram_page (unsigned long page)
- *
* Params : address Area start address
* : size size of area
* : flags b0 = I cache as well
- *
* Purpose : clean & flush all cache lines associated with this area of memory
*/
.align 5
@@ -176,7 +163,6 @@
/*
* Function: sa110_flush_tlb_all (void)
- *
* Purpose : flush all TLB entries in all caches
*/
.align 5
@@ -188,11 +174,9 @@
/*
* Function: sa110_flush_tlb_area (unsigned long address, unsigned long end, int flags)
- *
* Params : address Area start address
* : end Area end address
* : flags b0 = I cache as well
- *
* Purpose : flush a TLB entry
*/
.align 5
@@ -221,13 +205,10 @@
mov pc, lr
/*
* Function: sa110_switch_to (struct task_struct *prev, struct task_struct *next)
- *
* Params : prev Old task structure
* : next New task structure for process to run
- *
* Purpose : Perform a task switch, saving the old processes state, and restoring
* the new.
- *
* Notes : We don't fiddle with the FP registers here - we postpone this until
* the new task actually uses FP. This way, we don't swap FP for tasks
* that do not require it.
@@ -237,6 +218,7 @@
stmfd sp!, {r4 - r9, fp, lr} @ Store most regs on stack
mrs ip, cpsr
stmfd sp!, {ip} @ Save cpsr_SVC
+ ldr r2, [r0, #TSS_MEMMAP] @ Get old page tables
str sp, [r0, #TSS_SAVE] @ Save sp_SVC
ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC
ldr r0, [r1, #TSK_ADDR_LIMIT]
@@ -245,12 +227,25 @@
movne r0, #DOM_USERDOMAIN
mcr p15, 0, r0, c3, c0 @ Set segment
ldr r0, [r1, #TSS_MEMMAP] @ Page table pointer
+/*
+ * Flushing the cache is nightmarishly slow, so we take any excuse
+ * to get out of it. If the old page table is the same as the new,
+ * this is a CLONE_VM relative of the old task and there is no need
+ * to flush. The overhead of the tests isn't even on the radar
+ * compared to the cost of the flush itself.
+ */
+/*
+ * Disabled for the moment - it causes all sorts of havoc with
+ * kernel threads executing user commands (eg, kmod) - rmk
+ */
+ teq r0, r2
+ beq 2f
ldr r3, =Lclean_switch
ldr r2, [r3]
ands r2, r2, #1
eor r2, r2, #1
str r2, [r3]
- ldr r2, =0xdf000000
+ ldr r2, =FLUSH_BASE
addne r2, r2, #32768
add r1, r2, #16384 @ only necessary for 16k
1: ldr r3, [r2], #32
@@ -261,17 +256,14 @@
mcr p15, 0, r1, c7, c10, 4 @ drain WB
mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
mcr p15, 0, r1, c8, c7, 0 @ flush TLBs
- ldmfd sp!, {ip}
+2: ldmfd sp!, {ip}
msr spsr, ip @ Save tasks CPSR into SPSR for this return
ldmfd sp!, {r4 - r9, fp, pc}^ @ Load all regs saved previously
/*
* Function: sa110_data_abort ()
- *
* Params : r0 = address of aborted instruction
- *
* Purpose : obtain information about current aborted instruction
- *
* Returns : r0 = address of abort
* : r1 = FSR
* : r2 != 0 if writing
@@ -289,10 +281,8 @@
/*
* Function: sa110_set_pmd ()
- *
* Params : r0 = Address to set
* : r1 = value to set
- *
* Purpose : Set a PMD and flush it out of any WB cache
*/
.align 5
@@ -304,20 +294,19 @@
* Function: sa110_check_bugs (void)
* : sa110_proc_init (void)
* : sa110_proc_fin (void)
- *
* Notes : This processor does not require these
*/
_sa110_check_bugs:
mrs ip, cpsr
bic ip, ip, #F_BIT
msr cpsr, ip
+
_sa110_proc_init:
_sa110_proc_fin:
mov pc, lr
/*
* Function: sa110_reset
- *
* Notes : This sets up everything for a reset
*/
_sa110_reset: mrs r1, cpsr
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/mm/small_page.c linux.ac/arch/arm/mm/small_page.c
--- linux.vanilla/arch/arm/mm/small_page.c Sun Nov 8 15:08:45 1998
+++ linux.ac/arch/arm/mm/small_page.c Sun Feb 7 19:46:21 1999
@@ -5,6 +5,8 @@
*
* Changelog:
* 26/01/1996 RMK Cleaned up various areas to make little more generic
+ * 07/02/1999 RMK Support added for 16K and 32K page sizes
+ * containing 8K blocks
*/
#include
@@ -19,21 +21,31 @@
#include
#include
+#if PAGE_SIZE == 4096
+/* 1K blocks */
#define SMALL_ALLOC_SHIFT (10)
+#define NAME(x) x##_1k
+#elif PAGE_SIZE == 32768 || PAGE_SIZE == 16384
+/* 8K blocks */
+#define SMALL_ALLOC_SHIFT (13)
+#define NAME(x) x##_8k
+#endif
+
#define SMALL_ALLOC_SIZE (1 << SMALL_ALLOC_SHIFT)
#define NR_BLOCKS (PAGE_SIZE / SMALL_ALLOC_SIZE)
+#define BLOCK_MASK ((1 << NR_BLOCKS) - 1)
-#if NR_BLOCKS != 4
-#error I only support 4 blocks per page!
-#endif
-
-#define USED(pg) ((atomic_read(&(pg)->count) >> 8) & 15)
+#define USED(pg) ((atomic_read(&(pg)->count) >> 8) & BLOCK_MASK)
#define SET_USED(pg,off) (atomic_read(&(pg)->count) |= 256 << off)
#define CLEAR_USED(pg,off) (atomic_read(&(pg)->count) &= ~(256 << off))
#define IS_FREE(pg,off) (!(atomic_read(&(pg)->count) & (256 << off)))
#define PAGE_PTR(page,block) ((struct free_small_page *)((page) + \
((block) << SMALL_ALLOC_SHIFT)))
+#if NR_BLOCKS != 2 && NR_BLOCKS != 4
+#error I only support 2 or 4 blocks per page
+#endif
+
struct free_small_page {
unsigned long next;
unsigned long prev;
@@ -52,6 +64,7 @@
1, /* 0001 */
0, /* 0010 */
2, /* 0011 */
+#if NR_BLOCKS == 4
0, /* 0100 */
1, /* 0101 */
0, /* 0110 */
@@ -64,6 +77,7 @@
1, /* 1101 */
0, /* 1110 */
4 /* 1111 */
+#endif
};
static inline void clear_page_links(unsigned long page)
@@ -113,7 +127,7 @@
}
}
-unsigned long get_small_page(int priority)
+unsigned long NAME(get_page)(int priority)
{
struct free_small_page *fsp;
unsigned long new_page;
@@ -156,25 +170,26 @@
goto again;
}
-void free_small_page(unsigned long spage)
+void NAME(free_page)(unsigned long spage)
{
struct free_small_page *ofsp, *cfsp;
unsigned long flags;
struct page *page;
int offset, oldoffset;
+ if (!spage)
+ goto none;
+
offset = (spage >> SMALL_ALLOC_SHIFT) & (NR_BLOCKS - 1);
spage -= offset << SMALL_ALLOC_SHIFT;
page = mem_map + MAP_NR(spage);
- if (!PageReserved(page) || !USED(page)) {
- printk ("Trying to free non-small page from %p\n", __builtin_return_address(0));
- return;
- }
- if (IS_FREE(page, offset)) {
- printk ("Trying to free free small page from %p\n", __builtin_return_address(0));
- return;
- }
+ if (!PageReserved(page) || !USED(page))
+ goto non_small;
+
+ if (IS_FREE(page, offset))
+ goto free;
+
save_flags_cli (flags);
oldoffset = offsets[USED(page)];
CLEAR_USED(page, offset);
@@ -197,4 +212,13 @@
} else
*cfsp = *ofsp;
restore_flags(flags);
+ return;
+
+non_small:
+ printk ("Trying to free non-small page from %p\n", __builtin_return_address(0));
+ return;
+free:
+ printk ("Trying to free free small page from %p\n", __builtin_return_address(0));
+none:
+ return;
}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/ARM-gcc.h linux.ac/arch/arm/nwfpe/ARM-gcc.h
--- linux.vanilla/arch/arm/nwfpe/ARM-gcc.h Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/nwfpe/ARM-gcc.h Tue Feb 2 20:59:49 1999
@@ -0,0 +1,128 @@
+
+/*
+-------------------------------------------------------------------------------
+One of the macros `BIGENDIAN' or `LITTLEENDIAN' must be defined.
+-------------------------------------------------------------------------------
+*/
+#define LITTLEENDIAN
+
+/*
+-------------------------------------------------------------------------------
+The macro `BITS64' can be defined to indicate that 64-bit integer types are
+supported by the compiler.
+-------------------------------------------------------------------------------
+*/
+#define BITS64
+
+/*
+-------------------------------------------------------------------------------
+Each of the following `typedef's defines the most convenient type that holds
+integers of at least as many bits as specified. For example, `uint8' should
+be the most convenient type that can hold unsigned integers of as many as
+8 bits. The `flag' type must be able to hold either a 0 or 1. For most
+implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed
+to the same as `int'.
+-------------------------------------------------------------------------------
+*/
+typedef char flag;
+typedef unsigned char uint8;
+typedef signed char int8;
+typedef int uint16;
+typedef int int16;
+typedef unsigned int uint32;
+typedef signed int int32;
+#ifdef BITS64
+typedef unsigned long long int bits64;
+typedef signed long long int sbits64;
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Each of the following `typedef's defines a type that holds integers
+of _exactly_ the number of bits specified. For instance, for most
+implementation of C, `bits16' and `sbits16' should be `typedef'ed to
+`unsigned short int' and `signed short int' (or `short int'), respectively.
+-------------------------------------------------------------------------------
+*/
+typedef unsigned char bits8;
+typedef signed char sbits8;
+typedef unsigned short int bits16;
+typedef signed short int sbits16;
+typedef unsigned int bits32;
+typedef signed int sbits32;
+#ifdef BITS64
+typedef unsigned long long int uint64;
+typedef signed long long int int64;
+#endif
+
+#ifdef BITS64
+/*
+-------------------------------------------------------------------------------
+The `LIT64' macro takes as its argument a textual integer literal and if
+necessary ``marks'' the literal as having a 64-bit integer type. For
+example, the Gnu C Compiler (`gcc') requires that 64-bit literals be
+appended with the letters `LL' standing for `long long', which is `gcc's
+name for the 64-bit integer type. Some compilers may allow `LIT64' to be
+defined as the identity macro: `#define LIT64( a ) a'.
+-------------------------------------------------------------------------------
+*/
+#define LIT64( a ) a##LL
+#endif
+
+/*
+-------------------------------------------------------------------------------
+The macro `INLINE' can be used before functions that should be inlined. If
+a compiler does not support explicit inlining, this macro should be defined
+to be `static'.
+-------------------------------------------------------------------------------
+*/
+#define INLINE extern __inline__
+
+
+/* For use as a GCC soft-float library we need some special function names. */
+
+#ifdef __LIBFLOAT__
+
+/* Some 32-bit ops can be mapped straight across by just changing the name. */
+#define float32_add __addsf3
+#define float32_sub __subsf3
+#define float32_mul __mulsf3
+#define float32_div __divsf3
+#define int32_to_float32 __floatsisf
+#define float32_to_int32_round_to_zero __fixsfsi
+#define float32_to_uint32_round_to_zero __fixunssfsi
+
+/* These ones go through the glue code. To avoid namespace pollution
+ we rename the internal functions too. */
+#define float32_eq ___float32_eq
+#define float32_le ___float32_le
+#define float32_lt ___float32_lt
+
+/* All the 64-bit ops have to go through the glue, so we pull the same
+ trick. */
+#define float64_add ___float64_add
+#define float64_sub ___float64_sub
+#define float64_mul ___float64_mul
+#define float64_div ___float64_div
+#define int32_to_float64 ___int32_to_float64
+#define float64_to_int32_round_to_zero ___float64_to_int32_round_to_zero
+#define float64_to_uint32_round_to_zero ___float64_to_uint32_round_to_zero
+#define float64_to_float32 ___float64_to_float32
+#define float32_to_float64 ___float32_to_float64
+#define float64_eq ___float64_eq
+#define float64_le ___float64_le
+#define float64_lt ___float64_lt
+
+#if 0
+#define float64_add __adddf3
+#define float64_sub __subdf3
+#define float64_mul __muldf3
+#define float64_div __divdf3
+#define int32_to_float64 __floatsidf
+#define float64_to_int32_round_to_zero __fixdfsi
+#define float64_to_uint32_round_to_zero __fixunsdfsi
+#define float64_to_float32 __truncdfsf2
+#define float32_to_float64 __extendsfdf2
+#endif
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/ChangeLog linux.ac/arch/arm/nwfpe/ChangeLog
--- linux.vanilla/arch/arm/nwfpe/ChangeLog Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/nwfpe/ChangeLog Tue Feb 2 20:59:49 1999
@@ -0,0 +1,20 @@
+1998-11-23 Scott Bambrough
+
+ * README.FPE - fix typo in description of lfm/sfm instructions
+ * NOTES - Added file to describe known bugs/problems
+ * fpmodule.c - Changed version number to 0.94
+
+1998-11-20 Scott Bambrough
+
+ * README.FPE - fix description of URD, NRM instructions
+ * TODO - remove URD, NRM instructions from TODO list
+ * single_cpdo.c - implement URD, NRM
+ * double_cpdo.c - implement URD, NRM
+ * extended_cpdo.c - implement URD, NRM
+
+1998-11-19 Scott Bambrough
+
+ * ChangeLog - Added this file to track changes made.
+ * fpa11.c - added code to initialize register types to typeNone
+ * fpa11_cpdt.c - fixed bug in storeExtended (typeExtended changed to
+ typeDouble in switch statement)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/Makefile linux.ac/arch/arm/nwfpe/Makefile
--- linux.vanilla/arch/arm/nwfpe/Makefile Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/nwfpe/Makefile Tue Feb 2 20:59:49 1999
@@ -0,0 +1,33 @@
+#
+# linux/arch/arm/nwfpe/Makefile
+#
+# Copyright (C) 1998 Philip Blundell
+#
+
+CFLAGS += -freg-struct-return
+
+NWFPE_OBJS := fpa11.o fpa11_cpdo.o fpa11_cpdt.o fpa11_cprt.o \
+ fpmodule.o fpopcode.o softfloat.o \
+ single_cpdo.o double_cpdo.o extended_cpdo.o
+
+ifeq ($(CONFIG_CPU_26),y)
+NWFPE_OBJS += entry26.o
+else
+NWFPE_OBJS += entry.o
+endif
+
+L_TARGET := math-emu.a
+
+ifeq ($(CONFIG_NWFPE),y)
+L_OBJS = $(NWFPE_OBJS)
+else
+ ifeq ($(CONFIG_NWFPE),m)
+ M_OBJS = nwfpe.o
+ MI_OBJS = $(NWFPE_OBJS)
+ endif
+endif
+
+include $(TOPDIR)/Rules.make
+
+nwfpe.o: $(MI_OBJS) $(MIX_OBJS)
+ $(LD) $(LD_RFLAG) -r -o $@ $(MI_OBJS) $(MIX_OBJS)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/config.h linux.ac/arch/arm/nwfpe/config.h
--- linux.vanilla/arch/arm/nwfpe/config.h Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/nwfpe/config.h Tue Feb 2 20:59:49 1999
@@ -0,0 +1,31 @@
+/*
+ NetWinder Floating Point Emulator
+ (c) Corel Computer Corporation, 1998
+
+ Direct questions, comments to Scott Bambrough
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __CONFIG_H__
+#define __CONFIG_H__
+
+#if 1
+#define C_SYMBOL_NAME(foo) foo
+#else
+#define C_SYMBOL_NAME(foo) _##foo
+#endif
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/double_cpdo.c linux.ac/arch/arm/nwfpe/double_cpdo.c
--- linux.vanilla/arch/arm/nwfpe/double_cpdo.c Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/nwfpe/double_cpdo.c Tue Feb 2 20:59:49 1999
@@ -0,0 +1,283 @@
+/*
+ NetWinder Floating Point Emulator
+ (c) Corel Computer Corporation, 1998
+
+ Direct questions, comments to Scott Bambrough
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "config.h"
+#include "softfloat.h"
+#include "fpopcode.h"
+#include "fpa11.h"
+
+extern FPA11 *fpa11;
+
+float64 getDoubleConstant(unsigned int);
+
+float64 float64_exp(float64 Fm);
+float64 float64_ln(float64 Fm);
+float64 float64_sin(float64 rFm);
+float64 float64_cos(float64 rFm);
+float64 float64_arcsin(float64 rFm);
+float64 float64_arctan(float64 rFm);
+float64 float64_log(float64 rFm);
+float64 float64_tan(float64 rFm);
+float64 float64_arccos(float64 rFm);
+float64 float64_pow(float64 rFn,float64 rFm);
+float64 float64_pol(float64 rFn,float64 rFm);
+
+unsigned int DoubleCPDO(const unsigned int opcode)
+{
+ float64 rFm, rFn;
+ unsigned int Fd, Fm, Fn, nRc = 1;
+
+ //fp_printk("DoubleCPDO(0x%08x)\n",opcode);
+
+ Fm = getFm(opcode);
+ if (CONSTANT_FM(opcode))
+ {
+ rFm = getDoubleConstant(Fm);
+ }
+ else
+ {
+ switch (fpa11->fpreg[Fm].fType)
+ {
+ case typeSingle:
+ rFm = float32_to_float64(fpa11->fpreg[Fm].fValue.fSingle);
+ break;
+
+ case typeDouble:
+ rFm = fpa11->fpreg[Fm].fValue.fDouble;
+ break;
+
+ case typeExtended:
+ // !! patb
+ //fp_printk("not implemented! why not?\n");
+ //!! ScottB
+ // should never get here, if extended involved
+ // then other operand should be promoted then
+ // ExtendedCPDO called.
+ break;
+
+ default: return 0;
+ }
+ }
+
+ if (!MONADIC_INSTRUCTION(opcode))
+ {
+ Fn = getFn(opcode);
+ switch (fpa11->fpreg[Fn].fType)
+ {
+ case typeSingle:
+ rFn = float32_to_float64(fpa11->fpreg[Fn].fValue.fSingle);
+ break;
+
+ case typeDouble:
+ rFn = fpa11->fpreg[Fn].fValue.fDouble;
+ break;
+
+ default: return 0;
+ }
+ }
+
+ Fd = getFd(opcode);
+ /* !! this switch isn't optimized; better (opcode & MASK_ARITHMETIC_OPCODE)>>24, sort of */
+ switch (opcode & MASK_ARITHMETIC_OPCODE)
+ {
+ /* dyadic opcodes */
+ case ADF_CODE:
+ fpa11->fpreg[Fd].fValue.fDouble = float64_add(rFn,rFm);
+ break;
+
+ case MUF_CODE:
+ case FML_CODE:
+ fpa11->fpreg[Fd].fValue.fDouble = float64_mul(rFn,rFm);
+ break;
+
+ case SUF_CODE:
+ fpa11->fpreg[Fd].fValue.fDouble = float64_sub(rFn,rFm);
+ break;
+
+ case RSF_CODE:
+ fpa11->fpreg[Fd].fValue.fDouble = float64_sub(rFm,rFn);
+ break;
+
+ case DVF_CODE:
+ case FDV_CODE:
+ fpa11->fpreg[Fd].fValue.fDouble = float64_div(rFn,rFm);
+ break;
+
+ case RDF_CODE:
+ case FRD_CODE:
+ fpa11->fpreg[Fd].fValue.fDouble = float64_div(rFm,rFn);
+ break;
+
+ case POW_CODE:
+ fpa11->fpreg[Fd].fValue.fDouble = float64_pow(rFn,rFm);
+ break;
+
+ case RPW_CODE:
+ fpa11->fpreg[Fd].fValue.fDouble = float64_pow(rFm,rFn);
+ break;
+
+ case RMF_CODE:
+ fpa11->fpreg[Fd].fValue.fDouble = float64_rem(rFn,rFm);
+ break;
+
+ case POL_CODE:
+ fpa11->fpreg[Fd].fValue.fDouble = float64_pol(rFn,rFm);
+ break;
+
+ /* monadic opcodes */
+ case MVF_CODE:
+ fpa11->fpreg[Fd].fValue.fDouble = rFm;
+ break;
+
+ case MNF_CODE:
+ {
+ unsigned int *p = (unsigned int*)&rFm;
+ p[1] ^= 0x80000000;
+ fpa11->fpreg[Fd].fValue.fDouble = rFm;
+ }
+ break;
+
+ case ABS_CODE:
+ {
+ unsigned int *p = (unsigned int*)&rFm;
+ p[1] &= 0x7fffffff;
+ fpa11->fpreg[Fd].fValue.fDouble = rFm;
+ }
+ break;
+
+ case RND_CODE:
+ case URD_CODE:
+ fpa11->fpreg[Fd].fValue.fDouble =
+ int32_to_float64(float64_to_int32(rFm));
+ break;
+
+ case SQT_CODE:
+ fpa11->fpreg[Fd].fValue.fDouble = float64_sqrt(rFm);
+ break;
+
+ case LOG_CODE:
+ fpa11->fpreg[Fd].fValue.fDouble = float64_log(rFm);
+ break;
+
+ case LGN_CODE:
+ fpa11->fpreg[Fd].fValue.fDouble = float64_ln(rFm);
+ break;
+
+ case EXP_CODE:
+ fpa11->fpreg[Fd].fValue.fDouble = float64_exp(rFm);
+ break;
+
+ case SIN_CODE:
+ fpa11->fpreg[Fd].fValue.fDouble = float64_sin(rFm);
+ break;
+
+ case COS_CODE:
+ fpa11->fpreg[Fd].fValue.fDouble = float64_cos(rFm);
+ break;
+
+ case TAN_CODE:
+ fpa11->fpreg[Fd].fValue.fDouble = float64_tan(rFm);
+ break;
+
+ case ASN_CODE:
+ fpa11->fpreg[Fd].fValue.fDouble = float64_arcsin(rFm);
+ break;
+
+ case ACS_CODE:
+ fpa11->fpreg[Fd].fValue.fDouble = float64_arccos(rFm);
+ break;
+
+ case ATN_CODE:
+ fpa11->fpreg[Fd].fValue.fDouble = float64_arctan(rFm);
+ break;
+
+ case NRM_CODE:
+ break;
+
+ default:
+ {
+ nRc = 0;
+ }
+ }
+
+ if (0 != nRc) fpa11->fpreg[Fd].fType = typeDouble;
+ return nRc;
+}
+
+float64 float64_exp(float64 rFm)
+{
+ return rFm;
+//series
+}
+
+float64 float64_ln(float64 rFm)
+{
+ return rFm;
+//series
+}
+
+float64 float64_sin(float64 rFm)
+{
+ return rFm;
+//series
+}
+
+float64 float64_cos(float64 rFm)
+{
+ return rFm;
+ //series
+}
+
+float64 float64_arcsin(float64 rFm)
+{
+//series
+}
+
+float64 float64_arctan(float64 rFm)
+{
+ //series
+}
+
+float64 float64_log(float64 rFm)
+{
+ return float64_div(float64_ln(rFm),getDoubleConstant(7));
+}
+
+float64 float64_tan(float64 rFm)
+{
+ return float64_div(float64_sin(rFm),float64_cos(rFm));
+}
+
+float64 float64_arccos(float64 rFm)
+{
+return rFm;
+ //return float64_sub(halfPi,float64_arcsin(rFm));
+}
+
+float64 float64_pow(float64 rFn,float64 rFm)
+{
+ return float64_exp(float64_mul(rFm,float64_ln(rFn)));
+}
+
+float64 float64_pol(float64 rFn,float64 rFm)
+{
+ return float64_arctan(float64_div(rFn,rFm));
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/entry.S linux.ac/arch/arm/nwfpe/entry.S
--- linux.vanilla/arch/arm/nwfpe/entry.S Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/nwfpe/entry.S Tue Feb 2 20:59:49 1999
@@ -0,0 +1,115 @@
+/*
+ NetWinder Floating Point Emulator
+ (c) Corel Computer Corporation, 1998
+ (c) Philip Blundell 1998-1999
+
+ Direct questions, comments to Scott Bambrough
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* This is the kernel's entry point into the floating point emulator.
+It is called from the kernel with code similar to this:
+
+ adrsvc al, r9, ret_from_exception @ r9 = normal FP return
+ adrsvc al, lr, fpundefinstr @ lr = undefined instr return
+
+ get_current_task r10
+ mov r8, #1
+ strb r8, [r10, #TSK_USED_MATH] @ set current->used_math
+ add r10, r10, #TSS_FPESAVE @ r10 = workspace
+ ldr r4, .LC2
+ ldr pc, [r4] @ Call FP emulator entry point
+
+The kernel expects the emulator to return via one of two possible
+points of return it passes to the emulator. The emulator, if
+successful in its emulation, jumps to ret_from_exception (passed in
+r9) and the kernel takes care of returning control from the trap to
+the user code. If the emulator is unable to emulate the instruction,
+it returns via _fpundefinstr (passed via lr) and the kernel halts the
+user program with a core dump.
+
+On entry to the emulator r10 points to an area of private FP workspace
+reserved in the thread structure for this process. This is where the
+emulator saves its registers across calls. The first word of this area
+is used as a flag to detect the first time a process uses floating point,
+so that the emulator startup cost can be avoided for tasks that don't
+want it.
+
+This routine does three things:
+
+1) It saves SP into a variable called userRegisters. The kernel has
+created a struct pt_regs on the stack and saved the user registers
+into it. See /usr/include/asm/proc/ptrace.h for details. The
+emulator code uses userRegisters as the base of an array of words from
+which the contents of the registers can be extracted.
+
+2) It calls EmulateAll to emulate a floating point instruction.
+EmulateAll returns 1 if the emulation was successful, or 0 if not.
+
+3) If an instruction has been emulated successfully, it looks ahead at
+the next instruction. If it is a floating point instruction, it
+executes the instruction, without returning to user space. In this
+way it repeatedly looks ahead and executes floating point instructions
+until it encounters a non floating point instruction, at which time it
+returns via _fpreturn.
+
+This is done to reduce the effect of the trap overhead on each
+floating point instructions. GCC attempts to group floating point
+instructions to allow the emulator to spread the cost of the trap over
+several floating point instructions. */
+
+ .globl nwfpe_enter
+nwfpe_enter:
+ /* ?? Could put userRegisters and fpa11 into fixed regs during
+ emulation. This would reduce load/store overhead at the expense
+ of stealing two regs from the register allocator. Not sure if
+ it's worth it. */
+ ldr r4, =userRegisters
+ str sp, [r4] @ save pointer to user regs
+ ldr r4, =fpa11
+ str r10, [r4] @ store pointer to our state
+ mov r4, sp @ use r4 for local pointer
+ mov r10, lr @ save the failure-return addresses
+
+ ldr r5, [r4, #60] @ get contents of PC;
+ ldr r0, [r5, #-4] @ get actual instruction into r0
+emulate:
+ bl EmulateAll @ emulate the instruction
+ cmp r0, #0 @ was emulation successful
+ moveq pc, r10 @ no, return failure
+
+next:
+ ldr r6, [r5], #4 @ get the next instruction and
+ @ increment PC
+
+ and r2, r6, #0x0F000000 @ test for FP insns
+ teq r2, #0x0C000000
+ teqne r2, #0x0D000000
+ teqne r2, #0x0E000000
+ movne pc, r9 @ return ok if not a fp insn
+
+ str r5, [r4, #60] @ update PC copy in regs
+
+ mov r0, r6 @ save a copy
+ ldr r1, [r4, #64] @ fetch the condition codes
+ bl checkCondition @ check the condition
+ cmp r0, #0 @ r0 = 0 ==> condition failed
+
+ @ if condition code failed to match, next insn
+ beq next @ get the next instruction;
+
+ mov r0, r6 @ prepare for EmulateAll()
+ b emulate @ if r0 != 0, goto EmulateAll
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/entry26.S linux.ac/arch/arm/nwfpe/entry26.S
--- linux.vanilla/arch/arm/nwfpe/entry26.S Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/nwfpe/entry26.S Tue Feb 2 20:59:49 1999
@@ -0,0 +1,110 @@
+/*
+ NetWinder Floating Point Emulator
+ (c) Corel Computer Corporation, 1998
+ (c) Philip Blundell 1998-1999
+
+ Direct questions, comments to Scott Bambrough
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "../lib/constants.h"
+
+/* This is the kernel's entry point into the floating point emulator.
+It is called from the kernel with code similar to this:
+
+ mov fp, #0
+ teqp pc, #I_BIT | MODE_SVC
+ ldr r4, .LC2
+ ldr pc, [r4] @ Call FP module USR entry point
+
+The kernel expects the emulator to return via one of two possible
+points of return it passes to the emulator. The emulator, if
+successful in its emulation, jumps to ret_from_exception and the
+kernel takes care of returning control from the trap to the user code.
+If the emulator is unable to emulate the instruction, it returns to
+fpundefinstr and the kernel halts the user program with a core dump.
+
+This routine does four things:
+
+1) It saves SP into a variable called userRegisters. The kernel has
+created a struct pt_regs on the stack and saved the user registers
+into it. See /usr/include/asm/proc/ptrace.h for details. The
+emulator code uses userRegisters as the base of an array of words from
+which the contents of the registers can be extracted.
+
+2) It locates the FP emulator work area within the TSS structure and
+points `fpa11' to it.
+
+3) It calls EmulateAll to emulate a floating point instruction.
+EmulateAll returns 1 if the emulation was successful, or 0 if not.
+
+4) If an instruction has been emulated successfully, it looks ahead at
+the next instruction. If it is a floating point instruction, it
+executes the instruction, without returning to user space. In this
+way it repeatedly looks ahead and executes floating point instructions
+until it encounters a non floating point instruction, at which time it
+returns via _fpreturn.
+
+This is done to reduce the effect of the trap overhead on each
+floating point instructions. GCC attempts to group floating point
+instructions to allow the emulator to spread the cost of the trap over
+several floating point instructions. */
+
+ .globl nwfpe_enter
+nwfpe_enter:
+ ldr r4, =userRegisters
+ str sp, [r4] @ save pointer to user regs
+
+ mov r10, sp, lsr #13 @ find workspace
+ mov r10, r10, lsl #13
+ add r10, r10, #TSS_FPESAVE
+
+ ldr r4, =fpa11
+ str r10, [r4] @ store pointer to our state
+ mov r4, sp @ use r4 for local pointer
+
+ ldr r5, [r4, #60] @ get contents of PC
+ and r9, r5, #0xfc000003
+ eor r5, r5, r9
+ ldr r0, [r5, #-4] @ get actual instruction into r0
+emulate:
+ bl EmulateAll @ emulate the instruction
+ cmp r0, #0 @ was emulation successful
+ beq fpundefinstr @ no, return failure
+
+next:
+ ldr r6, [r5], #4 @ get the next instruction and
+ @ increment PC
+
+ and r2, r6, #0x0F000000 @ test for FP insns
+ teq r2, #0x0C000000
+ teqne r2, #0x0D000000
+ teqne r2, #0x0E000000
+ bne ret_from_exception @ return ok if not a fp insn
+
+ orr r7, r5, r9
+ str r7, [r4, #60] @ update PC copy in regs
+
+ mov r0, r6 @ save a copy
+ ldr r1, [r4, #64] @ fetch the condition codes
+ bl checkCondition @ check the condition
+ cmp r0, #0 @ r0 = 0 ==> condition failed
+
+ @ if condition code failed to match, next insn
+ beq next @ get the next instruction;
+
+ mov r0, r6 @ prepare for EmulateAll()
+ b emulate @ if r0 != 0, goto EmulateAll
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/extended_cpdo.c linux.ac/arch/arm/nwfpe/extended_cpdo.c
--- linux.vanilla/arch/arm/nwfpe/extended_cpdo.c Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/nwfpe/extended_cpdo.c Tue Feb 2 20:59:49 1999
@@ -0,0 +1,268 @@
+/*
+ NetWinder Floating Point Emulator
+ (c) Corel Computer Corporation, 1998
+
+ Direct questions, comments to Scott Bambrough
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "config.h"
+#include "softfloat.h"
+#include "fpopcode.h"
+#include "fpa11.h"
+
+floatx80 getExtendedConstant(unsigned int);
+
+floatx80 floatx80_exp(floatx80 Fm);
+floatx80 floatx80_ln(floatx80 Fm);
+floatx80 floatx80_sin(floatx80 rFm);
+floatx80 floatx80_cos(floatx80 rFm);
+floatx80 floatx80_arcsin(floatx80 rFm);
+floatx80 floatx80_arctan(floatx80 rFm);
+floatx80 floatx80_log(floatx80 rFm);
+floatx80 floatx80_tan(floatx80 rFm);
+floatx80 floatx80_arccos(floatx80 rFm);
+floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm);
+floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm);
+
+unsigned int ExtendedCPDO(const unsigned int opcode)
+{
+ floatx80 rFm, rFn;
+ unsigned int Fd, Fm, Fn, nRc = 1;
+
+ //fp_printk("ExtendedCPDO(0x%08x)\n",opcode);
+
+ Fm = getFm(opcode);
+ if (CONSTANT_FM(opcode))
+ {
+ rFm = getExtendedConstant(Fm);
+ }
+ else
+ {
+ switch (fpa11->fpreg[Fm].fType)
+ {
+ case typeSingle:
+ rFm = float32_to_floatx80(fpa11->fpreg[Fm].fValue.fSingle);
+ break;
+
+ case typeDouble:
+ rFm = float64_to_floatx80(fpa11->fpreg[Fm].fValue.fDouble);
+ break;
+
+ case typeExtended:
+ rFm = fpa11->fpreg[Fm].fValue.fExtended;
+ break;
+
+ default: return 0;
+ }
+ }
+
+ if (!MONADIC_INSTRUCTION(opcode))
+ {
+ Fn = getFn(opcode);
+ switch (fpa11->fpreg[Fn].fType)
+ {
+ case typeSingle:
+ rFn = float32_to_floatx80(fpa11->fpreg[Fn].fValue.fSingle);
+ break;
+
+ case typeDouble:
+ rFn = float64_to_floatx80(fpa11->fpreg[Fn].fValue.fDouble);
+ break;
+
+ case typeExtended:
+ rFn = fpa11->fpreg[Fn].fValue.fExtended;
+ break;
+
+ default: return 0;
+ }
+ }
+
+ Fd = getFd(opcode);
+ switch (opcode & MASK_ARITHMETIC_OPCODE)
+ {
+ /* dyadic opcodes */
+ case ADF_CODE:
+ fpa11->fpreg[Fd].fValue.fExtended = floatx80_add(rFn,rFm);
+ break;
+
+ case MUF_CODE:
+ case FML_CODE:
+ fpa11->fpreg[Fd].fValue.fExtended = floatx80_mul(rFn,rFm);
+ break;
+
+ case SUF_CODE:
+ fpa11->fpreg[Fd].fValue.fExtended = floatx80_sub(rFn,rFm);
+ break;
+
+ case RSF_CODE:
+ fpa11->fpreg[Fd].fValue.fExtended = floatx80_sub(rFm,rFn);
+ break;
+
+ case DVF_CODE:
+ case FDV_CODE:
+ fpa11->fpreg[Fd].fValue.fExtended = floatx80_div(rFn,rFm);
+ break;
+
+ case RDF_CODE:
+ case FRD_CODE:
+ fpa11->fpreg[Fd].fValue.fExtended = floatx80_div(rFm,rFn);
+ break;
+
+ case POW_CODE:
+ fpa11->fpreg[Fd].fValue.fExtended = floatx80_pow(rFn,rFm);
+ break;
+
+ case RPW_CODE:
+ fpa11->fpreg[Fd].fValue.fExtended = floatx80_pow(rFm,rFn);
+ break;
+
+ case RMF_CODE:
+ fpa11->fpreg[Fd].fValue.fExtended = floatx80_rem(rFn,rFm);
+ break;
+
+ case POL_CODE:
+ fpa11->fpreg[Fd].fValue.fExtended = floatx80_pol(rFn,rFm);
+ break;
+
+ /* monadic opcodes */
+ case MVF_CODE:
+ fpa11->fpreg[Fd].fValue.fExtended = rFm;
+ break;
+
+ case MNF_CODE:
+ rFm.high ^= 0x8000;
+ fpa11->fpreg[Fd].fValue.fExtended = rFm;
+ break;
+
+ case ABS_CODE:
+ rFm.high &= 0x7fff;
+ fpa11->fpreg[Fd].fValue.fExtended = rFm;
+ break;
+
+ case RND_CODE:
+ case URD_CODE:
+ fpa11->fpreg[Fd].fValue.fExtended =
+ int32_to_floatx80(floatx80_to_int32(rFm));
+ break;
+
+ case SQT_CODE:
+ fpa11->fpreg[Fd].fValue.fExtended = floatx80_sqrt(rFm);
+ break;
+
+ case LOG_CODE:
+ fpa11->fpreg[Fd].fValue.fExtended = floatx80_log(rFm);
+ break;
+
+ case LGN_CODE:
+ fpa11->fpreg[Fd].fValue.fExtended = floatx80_ln(rFm);
+ break;
+
+ case EXP_CODE:
+ fpa11->fpreg[Fd].fValue.fExtended = floatx80_exp(rFm);
+ break;
+
+ case SIN_CODE:
+ fpa11->fpreg[Fd].fValue.fExtended = floatx80_sin(rFm);
+ break;
+
+ case COS_CODE:
+ fpa11->fpreg[Fd].fValue.fExtended = floatx80_cos(rFm);
+ break;
+
+ case TAN_CODE:
+ fpa11->fpreg[Fd].fValue.fExtended = floatx80_tan(rFm);
+ break;
+
+ case ASN_CODE:
+ fpa11->fpreg[Fd].fValue.fExtended = floatx80_arcsin(rFm);
+ break;
+
+ case ACS_CODE:
+ fpa11->fpreg[Fd].fValue.fExtended = floatx80_arccos(rFm);
+ break;
+
+ case ATN_CODE:
+ fpa11->fpreg[Fd].fValue.fExtended = floatx80_arctan(rFm);
+ break;
+
+ case NRM_CODE:
+ break;
+
+ default:
+ {
+ nRc = 0;
+ }
+ }
+
+ if (0 != nRc) fpa11->fpreg[Fd].fType = typeExtended;
+ return nRc;
+}
+
+floatx80 floatx80_exp(floatx80 Fm)
+{
+//series
+}
+
+floatx80 floatx80_ln(floatx80 Fm)
+{
+//series
+}
+
+floatx80 floatx80_sin(floatx80 rFm)
+{
+//series
+}
+
+floatx80 floatx80_cos(floatx80 rFm)
+{
+//series
+}
+
+floatx80 floatx80_arcsin(floatx80 rFm)
+{
+//series
+}
+
+floatx80 floatx80_arctan(floatx80 rFm)
+{
+ //series
+}
+
+floatx80 floatx80_log(floatx80 rFm)
+{
+ return floatx80_div(floatx80_ln(rFm),getExtendedConstant(7));
+}
+
+floatx80 floatx80_tan(floatx80 rFm)
+{
+ return floatx80_div(floatx80_sin(rFm),floatx80_cos(rFm));
+}
+
+floatx80 floatx80_arccos(floatx80 rFm)
+{
+ //return floatx80_sub(halfPi,floatx80_arcsin(rFm));
+}
+
+floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm)
+{
+ return floatx80_exp(floatx80_mul(rFm,floatx80_ln(rFn)));
+}
+
+floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm)
+{
+ return floatx80_arctan(floatx80_div(rFn,rFm));
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/fpa11.c linux.ac/arch/arm/nwfpe/fpa11.c
--- linux.vanilla/arch/arm/nwfpe/fpa11.c Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/nwfpe/fpa11.c Tue Feb 2 20:59:49 1999
@@ -0,0 +1,206 @@
+/*
+ NetWinder Floating Point Emulator
+ (c) Corel Computer Corporation, 1998
+
+ Direct questions, comments to Scott Bambrough
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "config.h"
+#include "fpa11.h"
+#include "milieu.h"
+#include "fpopcode.h"
+
+#include "fpmodule.h"
+#include "fpmodule.inl"
+
+/* forward declarations */
+unsigned int EmulateCPDO(const unsigned int);
+unsigned int EmulateCPDT(const unsigned int);
+unsigned int EmulateCPRT(const unsigned int);
+
+/* Emulator registers */
+FPA11 *fpa11;
+
+/* Reset the FPA11 chip. Called to initialize and reset the emulator. */
+void resetFPA11(void)
+{
+ int i;
+ /* initialize the registers */
+ for (i=0;i<=7;i++)
+ {
+ fpa11->fpreg[i].fType = typeNone;
+ }
+
+ /* FPSR: set system id to FP_EMULATOR, clear all other bits */
+ fpa11->fpsr = FP_EMULATOR;
+
+ /* FPCR: set SB, AB and DA bits, clear all others */
+#if MAINTAIN_FPCR
+ fpa11->fpcr = MASK_RESET;
+#endif
+}
+
+void SetRoundingMode(const unsigned int opcode)
+{
+#if MAINTAIN_FPCR
+ fpa11->fpcr &= ~MASK_ROUNDING_MODE;
+#endif
+ switch (opcode & MASK_ROUNDING_MODE)
+ {
+ default:
+ case ROUND_TO_NEAREST:
+ float_rounding_mode = float_round_nearest_even;
+#if MAINTAIN_FPCR
+ fpa11->fpcr |= ROUND_TO_NEAREST;
+#endif
+ break;
+
+ case ROUND_TO_PLUS_INFINITY:
+ float_rounding_mode = float_round_up;
+#if MAINTAIN_FPCR
+ fpa11->fpcr |= ROUND_TO_PLUS_INFINITY;
+#endif
+ break;
+
+ case ROUND_TO_MINUS_INFINITY:
+ float_rounding_mode = float_round_down;
+#if MAINTAIN_FPCR
+ fpa11->fpcr |= ROUND_TO_MINUS_INFINITY;
+#endif
+ break;
+
+ case ROUND_TO_ZERO:
+ float_rounding_mode = float_round_to_zero;
+#if MAINTAIN_FPCR
+ fpa11->fpcr |= ROUND_TO_ZERO;
+#endif
+ break;
+ }
+}
+
+void SetRoundingPrecision(const unsigned int opcode)
+{
+#if MAINTAIN_FPCR
+ fpa11->fpcr &= ~MASK_ROUNDING_PRECISION;
+#endif
+ switch (opcode & MASK_ROUNDING_PRECISION)
+ {
+ case ROUND_SINGLE:
+ floatx80_rounding_precision = 32;
+#if MAINTAIN_FPCR
+ fpa11->fpcr |= ROUND_SINGLE;
+#endif
+ break;
+
+ case ROUND_DOUBLE:
+ floatx80_rounding_precision = 64;
+#if MAINTAIN_FPCR
+ fpa11->fpcr |= ROUND_DOUBLE;
+#endif
+ break;
+
+ case ROUND_EXTENDED:
+ floatx80_rounding_precision = 80;
+#if MAINTAIN_FPCR
+ fpa11->fpcr |= ROUND_EXTENDED;
+#endif
+ break;
+
+ default: floatx80_rounding_precision = 80;
+ }
+}
+
+/* Emulate the instruction in the opcode. */
+unsigned int EmulateAll(unsigned int opcode)
+{
+ unsigned int nRc = 0;
+
+ if (fpa11->initflag == 0) /* good place for __builtin_expect */
+ {
+ resetFPA11();
+ SetRoundingMode(ROUND_TO_NEAREST);
+ SetRoundingPrecision(ROUND_EXTENDED);
+ fpa11->initflag = 1;
+ }
+
+ if (TEST_OPCODE(opcode,MASK_CPRT))
+ {
+ /* Emulate conversion opcodes. */
+ /* Emulate register transfer opcodes. */
+ /* Emulate comparison opcodes. */
+ nRc = EmulateCPRT(opcode);
+ }
+ else if (TEST_OPCODE(opcode,MASK_CPDO))
+ {
+ /* Emulate monadic arithmetic opcodes. */
+ /* Emulate dyadic arithmetic opcodes. */
+ nRc = EmulateCPDO(opcode);
+ }
+ else if (TEST_OPCODE(opcode,MASK_CPDT))
+ {
+ /* Emulate load/store opcodes. */
+ /* Emulate load/store multiple opcodes. */
+ nRc = EmulateCPDT(opcode);
+ }
+ else
+ {
+ /* Invalid instruction detected. Return FALSE. */
+ nRc = 0;
+ }
+
+ return(nRc);
+}
+
+#if 0
+unsigned int EmulateAll1(unsigned int opcode)
+{
+ switch ((opcode >> 24) & 0xf)
+ {
+ case 0xc:
+ case 0xd:
+ if ((opcode >> 20) & 0x1)
+ {
+ switch ((opcode >> 8) & 0xf)
+ {
+ case 0x1: return PerformLDF(opcode); break;
+ case 0x2: return PerformLFM(opcode); break;
+ default: return 0;
+ }
+ }
+ else
+ {
+ switch ((opcode >> 8) & 0xf)
+ {
+ case 0x1: return PerformSTF(opcode); break;
+ case 0x2: return PerformSFM(opcode); break;
+ default: return 0;
+ }
+ }
+ break;
+
+ case 0xe:
+ if (opcode & 0x10)
+ return EmulateCPDO(opcode);
+ else
+ return EmulateCPRT(opcode);
+ break;
+
+ default: return 0;
+ }
+}
+#endif
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/fpa11.h linux.ac/arch/arm/nwfpe/fpa11.h
--- linux.vanilla/arch/arm/nwfpe/fpa11.h Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/nwfpe/fpa11.h Tue Feb 2 20:59:49 1999
@@ -0,0 +1,61 @@
+/*
+ NetWinder Floating Point Emulator
+ (c) Corel Computer Corporation, 1998
+
+ Direct questions, comments to Scott Bambrough
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __FPA11_H__
+#define __FPA11_H__
+
+/* includes */
+#include "fpsr.h" /* FP control and status register definitions */
+#include "softfloat.h"
+
+#define typeNone 0x00
+#define typeSingle 0x01
+#define typeDouble 0x02
+#define typeExtended 0x03
+
+typedef struct tagFPREG {
+ unsigned int fType;
+ union {
+ float32 fSingle;
+ float64 fDouble;
+ floatx80 fExtended;
+ } fValue;
+} FPREG;
+
+/* FPA11 device model */
+typedef struct tagFPA11 {
+ int initflag; /* this is special. The kernel guarantees
+ to set it to 0 when a thread is launched,
+ so we can use it to detect whether this
+ instance of the emulator needs to be
+ initialised. */
+ FPREG fpreg[8]; /* 8 floating point registers */
+ FPSR fpsr; /* floating point status register */
+ FPCR fpcr; /* floating point control register */
+} FPA11;
+
+extern void resetFPA11(void);
+extern void SetRoundingMode(const unsigned int);
+extern void SetRoundingPrecision(const unsigned int);
+
+extern FPA11 *fpa11;
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/fpa11.inl linux.ac/arch/arm/nwfpe/fpa11.inl
--- linux.vanilla/arch/arm/nwfpe/fpa11.inl Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/nwfpe/fpa11.inl Tue Feb 2 20:59:49 1999
@@ -0,0 +1,47 @@
+/*
+ NetWinder Floating Point Emulator
+ (c) Corel Computer Corporation, 1998
+
+ Direct questions, comments to Scott Bambrough
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "fpa11.h"
+
+/* Read and write floating point status register */
+extern __inline__ unsigned int readFPSR(void)
+{
+ return(fpa11->fpsr);
+}
+
+extern __inline__ void writeFPSR(FPSR reg)
+{
+ /* the sysid byte in the status register is readonly */
+ fpa11->fpsr = (fpa11->fpsr & MASK_SYSID) | (reg & ~MASK_SYSID);
+}
+
+/* Read and write floating point control register */
+extern __inline__ FPCR readFPCR(void)
+{
+ /* clear SB, AB and DA bits before returning FPCR */
+ return(fpa11->fpcr & ~MASK_RFC);
+}
+
+extern __inline__ void writeFPCR(FPCR reg)
+{
+ fpa11->fpcr &= ~MASK_WFC; /* clear SB, AB and DA bits */
+ fpa11->fpcr |= (reg & MASK_WFC); /* write SB, AB and DA bits */
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/fpa11_cpdo.c linux.ac/arch/arm/nwfpe/fpa11_cpdo.c
--- linux.vanilla/arch/arm/nwfpe/fpa11_cpdo.c Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/nwfpe/fpa11_cpdo.c Tue Feb 2 20:59:49 1999
@@ -0,0 +1,117 @@
+/*
+ NetWinder Floating Point Emulator
+ (c) Corel Computer Corporation, 1998
+
+ Direct questions, comments to Scott Bambrough
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "config.h"
+#include "fpa11.h"
+#include "fpopcode.h"
+
+unsigned int SingleCPDO(const unsigned int opcode);
+unsigned int DoubleCPDO(const unsigned int opcode);
+unsigned int ExtendedCPDO(const unsigned int opcode);
+
+unsigned int EmulateCPDO(const unsigned int opcode)
+{
+ unsigned int Fd, nType, nDest, nRc = 1;
+
+ //fp_printk("EmulateCPDO(0x%08x)\n",opcode);
+
+ /* Get the destination size. If not valid let Linux perform
+ an invalid instruction trap. */
+ nDest = getDestinationSize(opcode);
+ if (typeNone == nDest) return 0;
+
+ /* Compare the size of the operands in Fn and Fm.
+ Choose the largest size and perform operations in that size,
+ in order to make use of all the precision of the operands.
+ If Fm is a constant, we just grab a constant of a size
+ matching the size of the operand in Fn. */
+ if (MONADIC_INSTRUCTION(opcode))
+ nType = nDest;
+ else
+ nType = fpa11->fpreg[getFn(opcode)].fType;
+
+ if (!CONSTANT_FM(opcode))
+ {
+ register unsigned int Fm = getFm(opcode);
+ if (nType < fpa11->fpreg[Fm].fType)
+ {
+ nType = fpa11->fpreg[Fm].fType;
+ }
+ }
+
+ switch (nType)
+ {
+ case typeSingle : nRc = SingleCPDO(opcode); break;
+ case typeDouble : nRc = DoubleCPDO(opcode); break;
+ case typeExtended : nRc = ExtendedCPDO(opcode); break;
+ default : nRc = 0;
+ }
+
+ /* If the operation succeeded, check to see if the result in the
+ destination register is the correct size. If not force it
+ to be. */
+ Fd = getFd(opcode);
+ nType = fpa11->fpreg[Fd].fType;
+ if ((0 != nRc) && (nDest != nType))
+ {
+ SetRoundingMode(opcode);
+
+ switch (nDest)
+ {
+ case typeSingle:
+ {
+ if (typeDouble == nType)
+ fpa11->fpreg[Fd].fValue.fSingle =
+ float64_to_float32(fpa11->fpreg[Fd].fValue.fDouble);
+ else
+ fpa11->fpreg[Fd].fValue.fSingle =
+ floatx80_to_float32(fpa11->fpreg[Fd].fValue.fExtended);
+ }
+ break;
+
+ case typeDouble:
+ {
+ if (typeSingle == nType)
+ fpa11->fpreg[Fd].fValue.fDouble =
+ float32_to_float64(fpa11->fpreg[Fd].fValue.fSingle);
+ else
+ fpa11->fpreg[Fd].fValue.fDouble =
+ floatx80_to_float64(fpa11->fpreg[Fd].fValue.fExtended);
+ }
+ break;
+
+ case typeExtended:
+ {
+ if (typeSingle == nType)
+ fpa11->fpreg[Fd].fValue.fExtended =
+ float32_to_floatx80(fpa11->fpreg[Fd].fValue.fSingle);
+ else
+ fpa11->fpreg[Fd].fValue.fExtended =
+ float64_to_floatx80(fpa11->fpreg[Fd].fValue.fDouble);
+ }
+ break;
+ }
+
+ fpa11->fpreg[Fd].fType = nDest;
+ }
+
+ return nRc;
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/fpa11_cpdt.c linux.ac/arch/arm/nwfpe/fpa11_cpdt.c
--- linux.vanilla/arch/arm/nwfpe/fpa11_cpdt.c Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/nwfpe/fpa11_cpdt.c Tue Feb 2 20:59:49 1999
@@ -0,0 +1,330 @@
+/*
+ NetWinder Floating Point Emulator
+ (c) Corel Computer Corporation, 1998
+ (c) Philip Blundell, 1998
+
+ Direct questions, comments to Scott Bambrough
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "config.h"
+#include "softfloat.h"
+#include "fpopcode.h"
+#include "fpa11.h"
+#include "fpmodule.h"
+#include "fpmodule.inl"
+
+#include
+
+extern __inline__
+void loadSingle(const unsigned int Fn,const unsigned int *pMem)
+{
+ fpa11->fpreg[Fn].fType = typeSingle;
+ get_user(fpa11->fpreg[Fn].fValue.fSingle, pMem);
+}
+
+extern __inline__
+void loadDouble(const unsigned int Fn,const unsigned int *pMem)
+{
+ unsigned int *p;
+ p = (unsigned int*)&fpa11->fpreg[Fn].fValue.fDouble;
+ fpa11->fpreg[Fn].fType = typeDouble;
+ get_user(p[0], &pMem[1]);
+ get_user(p[1], &pMem[0]); /* sign & exponent */
+}
+
+extern __inline__
+void loadExtended(const unsigned int Fn,const unsigned int *pMem)
+{
+ unsigned int *p;
+ p = (unsigned int*)&fpa11->fpreg[Fn].fValue.fExtended;
+ fpa11->fpreg[Fn].fType = typeExtended;
+ get_user(p[0], &pMem[0]); /* sign & exponent */
+ get_user(p[1], &pMem[2]); /* ls bits */
+ get_user(p[2], &pMem[1]); /* ms bits */
+}
+
+extern __inline__
+void loadMultiple(const unsigned int Fn,const unsigned int *pMem)
+{
+ register unsigned int *p;
+ unsigned long x;
+
+ p = (unsigned int*)&(fpa11->fpreg[Fn].fValue);
+ get_user(x, &pMem[0]);
+ fpa11->fpreg[Fn].fType = (x >> 14) & 0x00000003;
+
+ switch (fpa11->fpreg[Fn].fType)
+ {
+ case typeSingle:
+ case typeDouble:
+ {
+ get_user(p[0], &pMem[2]); /* Single */
+ get_user(p[1], &pMem[1]); /* double msw */
+ p[2] = 0; /* empty */
+ }
+ break;
+
+ case typeExtended:
+ {
+ get_user(p[1], &pMem[2]);
+ get_user(p[2], &pMem[1]); /* msw */
+ p[0] = (x & 0x80003fff);
+ }
+ break;
+ }
+}
+
+extern __inline__
+void storeSingle(const unsigned int Fn,unsigned int *pMem)
+{
+ float32 val;
+ register unsigned int *p = (unsigned int*)&val;
+
+ switch (fpa11->fpreg[Fn].fType)
+ {
+ case typeDouble:
+ val = float64_to_float32(fpa11->fpreg[Fn].fValue.fDouble);
+ break;
+
+ case typeExtended:
+ val = floatx80_to_float32(fpa11->fpreg[Fn].fValue.fExtended);
+ break;
+
+ default: val = fpa11->fpreg[Fn].fValue.fSingle;
+ }
+
+ pMem[0] = p[0];
+}
+
+extern __inline__
+void storeDouble(const unsigned int Fn,unsigned int *pMem)
+{
+ float64 val;
+ register unsigned int *p = (unsigned int*)&val;
+
+ switch (fpa11->fpreg[Fn].fType)
+ {
+ case typeSingle:
+ val = float32_to_float64(fpa11->fpreg[Fn].fValue.fSingle);
+ break;
+
+ case typeExtended:
+ val = floatx80_to_float64(fpa11->fpreg[Fn].fValue.fExtended);
+ break;
+
+ default: val = fpa11->fpreg[Fn].fValue.fDouble;
+ }
+ put_user(p[1], &pMem[0]); /* msw */
+ put_user(p[0], &pMem[1]); /* lsw */
+}
+
+extern __inline__
+void storeExtended(const unsigned int Fn,unsigned int *pMem)
+{
+ floatx80 val;
+ register unsigned int *p = (unsigned int*)&val;
+
+ switch (fpa11->fpreg[Fn].fType)
+ {
+ case typeSingle:
+ val = float32_to_floatx80(fpa11->fpreg[Fn].fValue.fSingle);
+ break;
+
+ case typeDouble:
+ val = float64_to_floatx80(fpa11->fpreg[Fn].fValue.fDouble);
+ break;
+
+ default: val = fpa11->fpreg[Fn].fValue.fExtended;
+ }
+
+ put_user(p[0], &pMem[0]); /* sign & exp */
+ put_user(p[1], &pMem[2]);
+ put_user(p[2], &pMem[1]); /* msw */
+}
+
+extern __inline__
+void storeMultiple(const unsigned int Fn,unsigned int *pMem)
+{
+ register unsigned int nType, *p;
+
+ p = (unsigned int*)&(fpa11->fpreg[Fn].fValue);
+ nType = fpa11->fpreg[Fn].fType;
+
+ switch (nType)
+ {
+ case typeSingle:
+ case typeDouble:
+ {
+ put_user(p[0], &pMem[2]); /* single */
+ put_user(p[1], &pMem[1]); /* double msw */
+ put_user(nType << 14, &pMem[0]);
+ }
+ break;
+
+ case typeExtended:
+ {
+ put_user(p[2], &pMem[1]); /* msw */
+ put_user(p[1], &pMem[2]);
+ put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]);
+ }
+ break;
+ }
+}
+
+unsigned int PerformLDF(const unsigned int opcode)
+{
+ unsigned int *pBase, *pAddress, *pFinal, nRc = 1;
+
+ //fp_printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
+
+ pBase = (unsigned int*)readRegister(getRn(opcode));
+ if (REG_PC == getRn(opcode)) pBase += 2;
+
+ pFinal = pBase;
+ if (BIT_UP_SET(opcode))
+ pFinal += getOffset(opcode);
+ else
+ pFinal -= getOffset(opcode);
+
+ if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
+
+ switch (opcode & MASK_TRANSFER_LENGTH)
+ {
+ case TRANSFER_SINGLE : loadSingle(getFd(opcode),pAddress); break;
+ case TRANSFER_DOUBLE : loadDouble(getFd(opcode),pAddress); break;
+ case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break;
+ default: nRc = 0;
+ }
+
+ if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal);
+ return nRc;
+}
+
+unsigned int PerformSTF(const unsigned int opcode)
+{
+ unsigned int *pBase, *pAddress, *pFinal, nRc = 1;
+
+ //fp_printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
+ SetRoundingMode(ROUND_TO_NEAREST);
+
+ pBase = (unsigned int*)readRegister(getRn(opcode));
+ if (REG_PC == getRn(opcode)) pBase += 2;
+
+ pFinal = pBase;
+ if (BIT_UP_SET(opcode))
+ pFinal += getOffset(opcode);
+ else
+ pFinal -= getOffset(opcode);
+
+ if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
+
+ switch (opcode & MASK_TRANSFER_LENGTH)
+ {
+ case TRANSFER_SINGLE : storeSingle(getFd(opcode),pAddress); break;
+ case TRANSFER_DOUBLE : storeDouble(getFd(opcode),pAddress); break;
+ case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break;
+ default: nRc = 0;
+ }
+
+ if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal);
+ return nRc;
+}
+
+unsigned int PerformLFM(const unsigned int opcode)
+{
+ unsigned int i, Fd, *pBase, *pAddress, *pFinal;
+ pBase = (unsigned int*)readRegister(getRn(opcode));
+ if (REG_PC == getRn(opcode)) pBase += 2;
+
+ pFinal = pBase;
+ if (BIT_UP_SET(opcode))
+ pFinal += getOffset(opcode);
+ else
+ pFinal -= getOffset(opcode);
+
+ if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
+
+ Fd = getFd(opcode);
+ for (i=getRegisterCount(opcode);i>0;i--)
+ {
+ loadMultiple(Fd,pAddress);
+ pAddress += 3; Fd++;
+ if (Fd == 8) Fd = 0;
+ }
+
+ if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal);
+ return 1;
+}
+
+unsigned int PerformSFM(const unsigned int opcode)
+{
+ unsigned int i, Fd, *pBase, *pAddress, *pFinal;
+
+ pBase = (unsigned int*)readRegister(getRn(opcode));
+ if (REG_PC == getRn(opcode)) pBase += 2;
+
+ pFinal = pBase;
+ if (BIT_UP_SET(opcode))
+ pFinal += getOffset(opcode);
+ else
+ pFinal -= getOffset(opcode);
+
+ if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
+
+ Fd = getFd(opcode);
+ for (i=getRegisterCount(opcode);i>0;i--)
+ {
+ storeMultiple(Fd,pAddress);
+ pAddress += 3; Fd++;
+ if (Fd == 8) Fd = 0;
+ }
+
+ if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal);
+ return 1;
+}
+
+#if 1
+unsigned int EmulateCPDT(const unsigned int opcode)
+{
+ unsigned int nRc = 0;
+
+ //fp_printk("EmulateCPDT(0x%08x)\n",opcode);
+
+ if (LDF_OP(opcode))
+ {
+ nRc = PerformLDF(opcode);
+ }
+ else if (LFM_OP(opcode))
+ {
+ nRc = PerformLFM(opcode);
+ }
+ else if (STF_OP(opcode))
+ {
+ nRc = PerformSTF(opcode);
+ }
+ else if (SFM_OP(opcode))
+ {
+ nRc = PerformSFM(opcode);
+ }
+ else
+ {
+ nRc = 0;
+ }
+
+ return nRc;
+}
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/fpa11_cprt.c linux.ac/arch/arm/nwfpe/fpa11_cprt.c
--- linux.vanilla/arch/arm/nwfpe/fpa11_cprt.c Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/nwfpe/fpa11_cprt.c Tue Feb 2 20:59:49 1999
@@ -0,0 +1,302 @@
+/*
+ NetWinder Floating Point Emulator
+ (c) Corel Computer Corporation, 1998
+ (c) Philip Blundell, 1999
+
+ Direct questions, comments to Scott Bambrough
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "config.h"
+#include "milieu.h"
+#include "softfloat.h"
+#include "fpopcode.h"
+#include "fpa11.h"
+#include "fpa11.inl"
+#include "fpmodule.h"
+#include "fpmodule.inl"
+
+extern flag floatx80_is_nan(floatx80);
+extern flag float64_is_nan( float64);
+extern flag float32_is_nan( float32);
+
+void SetRoundingMode(const unsigned int opcode);
+
+unsigned int PerformFLT(const unsigned int opcode);
+unsigned int PerformFIX(const unsigned int opcode);
+
+static unsigned int
+PerformComparison(const unsigned int opcode);
+
+unsigned int EmulateCPRT(const unsigned int opcode)
+{
+ unsigned int nRc = 1;
+
+ //fp_printk("EmulateCPRT(0x%08x)\n",opcode);
+
+ if (opcode & 0x800000)
+ {
+ /* This is some variant of a comparison (PerformComparison will
+ sort out which one). Since most of the other CPRT
+ instructions are oddball cases of some sort or other it makes
+ sense to pull this out into a fast path. */
+ return PerformComparison(opcode);
+ }
+
+ /* Hint to GCC that we'd like a jump table rather than a load of CMPs */
+ switch ((opcode & 0x700000) >> 20)
+ {
+ case FLT_CODE >> 20: nRc = PerformFLT(opcode); break;
+ case FIX_CODE >> 20: nRc = PerformFIX(opcode); break;
+
+ case WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break;
+ case RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break;
+
+ /* ?? Not at all sure about the mode checks here. Linux never
+ calls the emulator from a non-USR fault but we always run in SVC
+ mode. Is there even any point trying to emulate the way FPA11
+ behaves in this respect? */
+ case WFC_CODE >> 20:
+ {
+ int mode = 0;
+ __asm__ volatile ("mrs %0, cpsr; and %0, %0, #0x1f;" : : "g" (mode));
+ nRc = (0x13 == mode) ? 1 : 0; /* in SVC processor mode? */
+ if (nRc) writeFPCR(readRegister(getRd(opcode)));
+ }
+ break;
+
+ case RFC_CODE >> 20:
+ {
+ int mode = 0;
+ __asm__ volatile ("mrs %0, cpsr; and %0, %0, #0x1f;" : : "g" (mode));
+ nRc = (0x13 == mode) ? 1 : 0; /* in SVC processor mode? */
+ if (nRc) writeRegister(getRd(opcode),readFPCR()); break;
+ }
+ break;
+
+ default: nRc = 0;
+ }
+
+ return nRc;
+}
+
+unsigned int PerformFLT(const unsigned int opcode)
+{
+ unsigned int nRc = 1;
+ SetRoundingMode(opcode);
+ SetRoundingPrecision(opcode);
+
+ switch (opcode & MASK_ROUNDING_PRECISION)
+ {
+ case ROUND_SINGLE:
+ {
+ fpa11->fpreg[getFn(opcode)].fType = typeSingle;
+ fpa11->fpreg[getFn(opcode)].fValue.fSingle =
+ int32_to_float32(readRegister(getRd(opcode)));
+ }
+ break;
+
+ case ROUND_DOUBLE:
+ {
+ fpa11->fpreg[getFn(opcode)].fType = typeDouble;
+ fpa11->fpreg[getFn(opcode)].fValue.fDouble =
+ int32_to_float64(readRegister(getRd(opcode)));
+ }
+ break;
+
+ case ROUND_EXTENDED:
+ {
+ fpa11->fpreg[getFn(opcode)].fType = typeExtended;
+ fpa11->fpreg[getFn(opcode)].fValue.fExtended =
+ int32_to_floatx80(readRegister(getRd(opcode)));
+ }
+ break;
+
+ default: nRc = 0;
+ }
+
+ return nRc;
+}
+
+unsigned int PerformFIX(const unsigned int opcode)
+{
+ unsigned int nRc = 1;
+ unsigned int Fn = getFm(opcode);
+
+ SetRoundingMode(opcode);
+
+ switch (fpa11->fpreg[Fn].fType)
+ {
+ case typeSingle:
+ {
+ writeRegister(getRd(opcode),
+ float32_to_int32(fpa11->fpreg[Fn].fValue.fSingle));
+ }
+ break;
+
+ case typeDouble:
+ {
+ writeRegister(getRd(opcode),
+ float64_to_int32(fpa11->fpreg[Fn].fValue.fDouble));
+ }
+ break;
+
+ case typeExtended:
+ {
+ writeRegister(getRd(opcode),
+ floatx80_to_int32(fpa11->fpreg[Fn].fValue.fExtended));
+ }
+ break;
+
+ default: nRc = 0;
+ }
+
+ return nRc;
+}
+
+
+static unsigned int __inline__
+PerformComparisonOperation(floatx80 Fn, floatx80 Fm)
+{
+ unsigned int flags = 0;
+
+ /* test for less than condition */
+ if (floatx80_lt(Fn,Fm))
+ {
+ flags |= CC_NEGATIVE;
+ }
+
+ /* test for equal condition */
+ if (floatx80_eq(Fn,Fm))
+ {
+ flags |= CC_ZERO;
+ }
+
+ /* test for greater than or equal condition */
+ if (floatx80_lt(Fm,Fn))
+ {
+ flags |= CC_CARRY;
+ }
+
+ writeConditionCodes(flags);
+ return 1;
+}
+
+/* This instruction sets the flags N, Z, C, V in the FPSR. */
+
+static unsigned int PerformComparison(const unsigned int opcode)
+{
+ unsigned int Fn, Fm;
+ floatx80 rFn, rFm;
+ int e_flag = opcode & 0x400000; /* 1 if CxFE */
+ int n_flag = opcode & 0x200000; /* 1 if CNxx */
+ unsigned int flags = 0;
+
+ //fp_printk("PerformComparison(0x%08x)\n",opcode);
+
+ Fn = getFn(opcode);
+ Fm = getFm(opcode);
+
+ /* Check for unordered condition and convert all operands to 80-bit
+ format.
+ ?? Might be some mileage in avoiding this conversion if possible.
+ Eg, if both operands are 32-bit, detect this and do a 32-bit
+ comparison (cheaper than an 80-bit one). */
+ switch (fpa11->fpreg[Fn].fType)
+ {
+ case typeSingle:
+ //fp_printk("single.\n");
+ if (float32_is_nan(fpa11->fpreg[Fn].fValue.fSingle))
+ goto unordered;
+ rFn = float32_to_floatx80(fpa11->fpreg[Fn].fValue.fSingle);
+ break;
+
+ case typeDouble:
+ //fp_printk("double.\n");
+ if (float64_is_nan(fpa11->fpreg[Fn].fValue.fDouble))
+ goto unordered;
+ rFn = float64_to_floatx80(fpa11->fpreg[Fn].fValue.fDouble);
+ break;
+
+ case typeExtended:
+ //fp_printk("extended.\n");
+ if (floatx80_is_nan(fpa11->fpreg[Fn].fValue.fExtended))
+ goto unordered;
+ rFn = fpa11->fpreg[Fn].fValue.fExtended;
+ break;
+
+ default: return 0;
+ }
+
+ if (CONSTANT_FM(opcode))
+ {
+ //fp_printk("Fm is a constant: #%d.\n",Fm);
+ rFm = getExtendedConstant(Fm);
+ if (floatx80_is_nan(rFm))
+ goto unordered;
+ }
+ else
+ {
+ //fp_printk("Fm = r%d which contains a ",Fm);
+ switch (fpa11->fpreg[Fm].fType)
+ {
+ case typeSingle:
+ //fp_printk("single.\n");
+ if (float32_is_nan(fpa11->fpreg[Fm].fValue.fSingle))
+ goto unordered;
+ rFm = float32_to_floatx80(fpa11->fpreg[Fm].fValue.fSingle);
+ break;
+
+ case typeDouble:
+ //fp_printk("double.\n");
+ if (float64_is_nan(fpa11->fpreg[Fm].fValue.fDouble))
+ goto unordered;
+ rFm = float64_to_floatx80(fpa11->fpreg[Fm].fValue.fDouble);
+ break;
+
+ case typeExtended:
+ //fp_printk("extended.\n");
+ if (floatx80_is_nan(fpa11->fpreg[Fm].fValue.fExtended))
+ goto unordered;
+ rFm = fpa11->fpreg[Fm].fValue.fExtended;
+ break;
+
+ default: return 0;
+ }
+ }
+
+ if (n_flag)
+ {
+ rFm.high ^= 0x8000;
+ }
+
+ return PerformComparisonOperation(rFn,rFm);
+
+ unordered:
+ /* ?? The FPA data sheet is pretty vague about this, in particular
+ about whether the non-E comparisons can ever raise exceptions.
+ This implementation is based on a combination of what it says in
+ the data sheet, observation of how the Acorn emulator actually
+ behaves (and how programs expect it to) and guesswork. */
+ flags |= CC_OVERFLOW;
+
+ if (BIT_AC & readFPSR()) flags |= CC_CARRY;
+
+ if (e_flag) float_raise(float_flag_invalid);
+
+ writeConditionCodes(flags);
+ return 1;
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/fpmodule.c linux.ac/arch/arm/nwfpe/fpmodule.c
--- linux.vanilla/arch/arm/nwfpe/fpmodule.c Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/nwfpe/fpmodule.c Wed Feb 17 20:56:57 1999
@@ -0,0 +1,167 @@
+/*
+ NetWinder Floating Point Emulator
+ (c) Corel Computer Corporation, 1998
+ (c) Philip Blundell, 1998-1999
+
+ Direct questions, comments to Scott Bambrough
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "config.h"
+
+#ifdef MODULE
+#include
+#include
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+/* XXX */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+/* XXX */
+
+#include "softfloat.h"
+#include "fpopcode.h"
+#include "fpmodule.h"
+#include "fpa11.h"
+#include "fpa11.inl"
+
+/* external data */
+extern FPA11 *fpa11;
+
+/* kernel symbols required for signal handling */
+typedef struct task_struct* PTASK;
+
+#ifdef MODULE
+int fp_printk(const char *,...);
+void fp_send_sig(unsigned long sig, PTASK p, int priv);
+#if LINUX_VERSION_CODE > 0x20115
+MODULE_AUTHOR("Scott Bambrough ");
+MODULE_DESCRIPTION("NWFPE floating point emulator");
+#endif
+
+#else
+#define fp_printk printk
+#define fp_send_sig send_sig
+#define kern_fp_enter fp_enter
+#endif
+
+/* kernel function prototypes required */
+void C_SYMBOL_NAME(fp_setup)(void);
+
+/* external declarations for saved kernel symbols */
+extern unsigned int C_SYMBOL_NAME(kern_fp_enter);
+
+/* forward declarations */
+extern void nwfpe_enter(void);
+
+/* Original value of fp_enter from kernel before patched by fpe_init. */
+static unsigned int orig_fp_enter;
+
+/* Address of user registers on the kernel stack. */
+unsigned int *userRegisters;
+
+void __init C_SYMBOL_NAME(fpe_version)(void)
+{
+ static const char szTitle[] = "<4>NetWinder Floating Point Emulator ";
+ static const char szVersion[] = "V0.94.1 ";
+ static const char szCopyright[] = "(c) 1998 Corel Computer Corp.\n";
+ C_SYMBOL_NAME(fp_printk)(szTitle);
+ C_SYMBOL_NAME(fp_printk)(szVersion);
+ C_SYMBOL_NAME(fp_printk)(szCopyright);
+}
+
+int __init fpe_init(void)
+{
+ /* Display title, version and copyright information. */
+ C_SYMBOL_NAME(fpe_version)();
+
+ /* Save pointer to the old FP handler and then patch ourselves in */
+ orig_fp_enter = C_SYMBOL_NAME(kern_fp_enter);
+ C_SYMBOL_NAME(kern_fp_enter) = (unsigned int)C_SYMBOL_NAME(nwfpe_enter);
+
+ return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return(fpe_init());
+}
+
+void cleanup_module(void)
+{
+ /* Restore the values we saved earlier. */
+ C_SYMBOL_NAME(kern_fp_enter) = orig_fp_enter;
+}
+#endif
+
+#define _ARM_pc 60
+#define _ARM_cpsr 64
+
+/*
+ScottB: November 4, 1998
+
+Moved this function out of softfloat-specialize into fpmodule.c.
+This effectively isolates all the changes required for integrating with the
+Linux kernel into fpmodule.c. Porting to NetBSD should only require modifying
+fpmodule.c to integrate with the NetBSD kernel (I hope!).
+
+[1/1/99: Not quite true any more unfortunately. There is Linux-specific
+code to access data in user space in some other source files at the
+moment. --philb]
+
+float_exception_flags is a global variable in SoftFloat.
+
+This function is called by the SoftFloat routines to raise a floating
+point exception. We check the trap enable byte in the FPSR, and raise
+a SIGFPE exception if necessary. If not the relevant bits in the
+cumulative exceptions flag byte are set and we return.
+*/
+
+void float_raise(signed char flags)
+{
+#if 0
+ printk(KERN_DEBUG "NWFPE: exception %08x at %08x from %08x\n", flags,
+ __builtin_return_address(0), userRegisters[15]);
+#endif
+
+ float_exception_flags |= flags;
+ if (readFPSR() & (flags << 16))
+ {
+ /* raise exception */
+ C_SYMBOL_NAME(fp_send_sig)(SIGFPE,C_SYMBOL_NAME(current),1);
+ }
+ else
+ {
+ /* set the cumulative exceptions flags */
+ writeFPSR(flags);
+ }
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/fpmodule.h linux.ac/arch/arm/nwfpe/fpmodule.h
--- linux.vanilla/arch/arm/nwfpe/fpmodule.h Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/nwfpe/fpmodule.h Tue Feb 2 20:59:49 1999
@@ -0,0 +1,45 @@
+/*
+ NetWinder Floating Point Emulator
+ (c) Corel Computer Corporation, 1998
+
+ Direct questions, comments to Scott Bambrough
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __FPMODULE_H__
+#define __FPMODULE_H__
+
+#define REG_ORIG_R0 17
+#define REG_CPSR 16
+#define REG_PC 15
+#define REG_LR 14
+#define REG_SP 13
+#define REG_IP 12
+#define REG_FP 11
+#define REG_R10 10
+#define REG_R9 9
+#define REG_R9 9
+#define REG_R8 8
+#define REG_R7 7
+#define REG_R6 6
+#define REG_R5 5
+#define REG_R4 4
+#define REG_R3 3
+#define REG_R2 2
+#define REG_R1 1
+#define REG_R0 0
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/fpmodule.inl linux.ac/arch/arm/nwfpe/fpmodule.inl
--- linux.vanilla/arch/arm/nwfpe/fpmodule.inl Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/nwfpe/fpmodule.inl Tue Feb 2 20:59:49 1999
@@ -0,0 +1,78 @@
+/*
+ NetWinder Floating Point Emulator
+ (c) Corel Computer Corporation, 1998
+
+ Direct questions, comments to Scott Bambrough
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* Address of user registers on the kernel stack. */
+extern unsigned int *userRegisters;
+
+extern __inline__
+unsigned int readRegister(const unsigned int nReg)
+{
+ /* Note: The CPU thinks it has dealt with the current instruction. As
+ a result the program counter has been advanced to the next
+ instruction, and points 4 bytes beyond the actual instruction
+ that caused the invalid instruction trap to occur. We adjust
+ for this in this routine. LDF/STF instructions with Rn = PC
+ depend on the PC being correct, as they use PC+8 in their
+ address calculations. */
+ unsigned int val = userRegisters[nReg];
+ if (REG_PC == nReg) val -= 4;
+ return val;
+}
+
+extern __inline__
+void writeRegister(const unsigned int nReg, const unsigned int val)
+{
+ userRegisters[nReg] = val;
+}
+
+extern __inline__
+unsigned int readCPSR(void)
+{
+ return(readRegister(REG_CPSR));
+}
+
+extern __inline__
+void writeCPSR(const unsigned int val)
+{
+ writeRegister(REG_CPSR,val);
+}
+
+extern __inline__
+unsigned int readConditionCodes(void)
+{
+#ifdef __FPEM_TEST__
+ return(0);
+#else
+ return(readCPSR() & CC_MASK);
+#endif
+}
+
+extern __inline__
+void writeConditionCodes(const unsigned int val)
+{
+ writeCPSR((readCPSR() & ~CC_MASK) | (val & CC_MASK));
+}
+
+extern __inline__
+unsigned int readMemoryInt(unsigned int *pMem)
+{
+ return *pMem;
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/fpopcode.c linux.ac/arch/arm/nwfpe/fpopcode.c
--- linux.vanilla/arch/arm/nwfpe/fpopcode.c Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/nwfpe/fpopcode.c Tue Feb 2 20:59:49 1999
@@ -0,0 +1,164 @@
+/*
+ NetWinder Floating Point Emulator
+ (c) Corel Computer Corporation, 1998
+
+ Direct questions, comments to Scott Bambrough
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "config.h"
+#include "softfloat.h"
+#include "fpopcode.h"
+#include "fpsr.h"
+#include "fpa11.h"
+#include "fpmodule.h"
+#include "fpmodule.inl"
+
+static floatx80 floatx80Constant[] = {
+ { 0x0000, 0x0000000000000000ULL}, /* extended 0.0 */
+ { 0x3fff, 0x8000000000000000ULL}, /* extended 1.0 */
+ { 0x4000, 0x8000000000000000ULL}, /* extended 2.0 */
+ { 0x4000, 0xc000000000000000ULL}, /* extended 3.0 */
+ { 0x4001, 0x8000000000000000ULL}, /* extended 4.0 */
+ { 0x4001, 0xa000000000000000ULL}, /* extended 5.0 */
+ { 0x3ffe, 0x8000000000000000ULL}, /* extended 0.5 */
+ { 0x4002, 0xa000000000000000ULL} /* extended 10.0 */
+};
+
+static float64 float64Constant[] = {
+ 0x0000000000000000ULL, /* double 0.0 */
+ 0x3ff0000000000000ULL, /* double 1.0 */
+ 0x4000000000000000ULL, /* double 2.0 */
+ 0x4008000000000000ULL, /* double 3.0 */
+ 0x4010000000000000ULL, /* double 4.0 */
+ 0x4014000000000000ULL, /* double 5.0 */
+ 0x3fe0000000000000ULL, /* double 0.5 */
+ 0x4024000000000000ULL /* double 10.0 */
+};
+
+static float32 float32Constant[] = {
+ 0x00000000, /* single 0.0 */
+ 0x3f800000, /* single 1.0 */
+ 0x40000000, /* single 2.0 */
+ 0x40400000, /* single 3.0 */
+ 0x40800000, /* single 4.0 */
+ 0x40a00000, /* single 5.0 */
+ 0x3f000000, /* single 0.5 */
+ 0x41200000 /* single 10.0 */
+};
+
+floatx80 getExtendedConstant(const unsigned int nIndex)
+{
+ return floatx80Constant[nIndex];
+}
+
+float64 getDoubleConstant(const unsigned int nIndex)
+{
+ return float64Constant[nIndex];
+}
+
+float32 getSingleConstant(const unsigned int nIndex)
+{
+ return float32Constant[nIndex];
+}
+
+unsigned int getTransferLength(const unsigned int opcode)
+{
+ unsigned int nRc;
+
+ switch (opcode & MASK_TRANSFER_LENGTH)
+ {
+ case 0x00000000: nRc = 1; break; /* single precision */
+ case 0x00008000: nRc = 2; break; /* double precision */
+ case 0x00400000: nRc = 3; break; /* extended precision */
+ default: nRc = 0;
+ }
+
+ return(nRc);
+}
+
+unsigned int getRegisterCount(const unsigned int opcode)
+{
+ unsigned int nRc;
+
+ switch (opcode & MASK_REGISTER_COUNT)
+ {
+ case 0x00000000: nRc = 4; break;
+ case 0x00008000: nRc = 1; break;
+ case 0x00400000: nRc = 2; break;
+ case 0x00408000: nRc = 3; break;
+ default: nRc = 0;
+ }
+
+ return(nRc);
+}
+
+unsigned int getRoundingPrecision(const unsigned int opcode)
+{
+ unsigned int nRc;
+
+ switch (opcode & MASK_ROUNDING_PRECISION)
+ {
+ case 0x00000000: nRc = 1; break;
+ case 0x00000080: nRc = 2; break;
+ case 0x00080000: nRc = 3; break;
+ default: nRc = 0;
+ }
+
+ return(nRc);
+}
+
+unsigned int getDestinationSize(const unsigned int opcode)
+{
+ unsigned int nRc;
+
+ switch (opcode & MASK_DESTINATION_SIZE)
+ {
+ case 0x00000000: nRc = typeSingle; break;
+ case 0x00000080: nRc = typeDouble; break;
+ case 0x00080000: nRc = typeExtended; break;
+ default: nRc = typeNone;
+ }
+
+ return(nRc);
+}
+
+/* contition code lookup table
+ index into the table is test code: EQ, NE, ... LT, GT, AL, NV
+ bit position in short is condition code: NZCV */
+unsigned short aCC[16] = {
+ 0xF0F0, // EQ == Z set
+ 0x0F0F, // NE
+ 0xCCCC, // CS == C set
+ 0x3333, // CC
+ 0xFF00, // MI == N set
+ 0x00FF, // PL
+ 0xAAAA, // VS == V set
+ 0x5555, // VC
+ 0x0C0C, // HI == C set && Z clear
+ 0xF3F3, // LS == C clear || Z set
+ 0xAA55, // GE == (N==V)
+ 0x55AA, // LT == (N!=V)
+ 0x0A05, // GT == (!Z && (N==V))
+ 0xF5FA, // LE == (Z || (N!=V))
+ 0xFFFF, // AL always
+ 0 // NV
+};
+
+unsigned int checkCondition(const unsigned int opcode, const unsigned int ccodes)
+{
+ return (aCC[opcode>>28] >> (ccodes>>28)) & 1;
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/fpopcode.h linux.ac/arch/arm/nwfpe/fpopcode.h
--- linux.vanilla/arch/arm/nwfpe/fpopcode.h Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/nwfpe/fpopcode.h Tue Feb 2 20:59:49 1999
@@ -0,0 +1,376 @@
+/*
+ NetWinder Floating Point Emulator
+ (c) Corel Computer Corporation, 1998
+
+ Direct questions, comments to Scott Bambrough
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __FPOPCODE_H__
+#define __FPOPCODE_H__
+
+/*
+ARM Floating Point Instruction Classes
+| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
+|c o n d|1 1 0 P|U|u|W|L| Rn |v| Fd |0|0|0|1| o f f s e t | CPDT
+|c o n d|1 1 0 P|U|w|W|L| Rn |x| Fd |0|0|0|1| o f f s e t | CPDT
+| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
+|c o n d|1 1 1 0|a|b|c|d|e| Fn |j| Fd |0|0|0|1|f|g|h|0|i| Fm | CPDO
+|c o n d|1 1 1 0|a|b|c|L|e| Fn | Rd |0|0|0|1|f|g|h|1|i| Fm | CPRT
+|c o n d|1 1 1 0|a|b|c|1|e| Fn |1|1|1|1|0|0|0|1|f|g|h|1|i| Fm | comparisons
+| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
+
+CPDT data transfer instructions
+ LDF, STF, LFM, SFM
+
+CPDO dyadic arithmetic instructions
+ ADF, MUF, SUF, RSF, DVF, RDF,
+ POW, RPW, RMF, FML, FDV, FRD, POL
+
+CPDO monadic arithmetic instructions
+ MVF, MNF, ABS, RND, SQT, LOG, LGN, EXP,
+ SIN, COS, TAN, ASN, ACS, ATN, URD, NRM
+
+CPRT joint arithmetic/data transfer instructions
+ FIX (arithmetic followed by load/store)
+ FLT (load/store followed by arithmetic)
+ CMF, CNF CMFE, CNFE (comparisons)
+ WFS, RFS (write/read floating point status register)
+ WFC, RFC (write/read floating point control register)
+
+cond condition codes
+P pre/post index bit: 0 = postindex, 1 = preindex
+U up/down bit: 0 = stack grows down, 1 = stack grows up
+W write back bit: 1 = update base register (Rn)
+L load/store bit: 0 = store, 1 = load
+Rn base register
+Rd destination/source register
+Fd floating point destination register
+Fn floating point source register
+Fm floating point source register or floating point constant
+
+uv transfer length (TABLE 1)
+wx register count (TABLE 2)
+abcd arithmetic opcode (TABLES 3 & 4)
+ef destination size (rounding precision) (TABLE 5)
+gh rounding mode (TABLE 6)
+j dyadic/monadic bit: 0 = dyadic, 1 = monadic
+i constant bit: 1 = constant (TABLE 6)
+*/
+
+/*
+TABLE 1
++-------------------------+---+---+---------+---------+
+| Precision | u | v | FPSR.EP | length |
++-------------------------+---+---+---------+---------+
+| Single | 0 ü 0 | x | 1 words |
+| Double | 1 ü 1 | x | 2 words |
+| Extended | 1 ü 1 | x | 3 words |
+| Packed decimal | 1 ü 1 | 0 | 3 words |
+| Expanded packed decimal | 1 ü 1 | 1 | 4 words |
++-------------------------+---+---+---------+---------+
+Note: x = don't care
+*/
+
+/*
+TABLE 2
++---+---+---------------------------------+
+| w | x | Number of registers to transfer |
++---+---+---------------------------------+
+| 0 ü 1 | 1 |
+| 1 ü 0 | 2 |
+| 1 ü 1 | 3 |
+| 0 ü 0 | 4 |
++---+---+---------------------------------+
+*/
+
+/*
+TABLE 3: Dyadic Floating Point Opcodes
++---+---+---+---+----------+-----------------------+-----------------------+
+| a | b | c | d | Mnemonic | Description | Operation |
++---+---+---+---+----------+-----------------------+-----------------------+
+| 0 | 0 | 0 | 0 | ADF | Add | Fd := Fn + Fm |
+| 0 | 0 | 0 | 1 | MUF | Multiply | Fd := Fn * Fm |
+| 0 | 0 | 1 | 0 | SUF | Subtract | Fd := Fn - Fm |
+| 0 | 0 | 1 | 1 | RSF | Reverse subtract | Fd := Fm - Fn |
+| 0 | 1 | 0 | 0 | DVF | Divide | Fd := Fn / Fm |
+| 0 | 1 | 0 | 1 | RDF | Reverse divide | Fd := Fm / Fn |
+| 0 | 1 | 1 | 0 | POW | Power | Fd := Fn ^ Fm |
+| 0 | 1 | 1 | 1 | RPW | Reverse power | Fd := Fm ^ Fn |
+| 1 | 0 | 0 | 0 | RMF | Remainder | Fd := IEEE rem(Fn/Fm) |
+| 1 | 0 | 0 | 1 | FML | Fast Multiply | Fd := Fn * Fm |
+| 1 | 0 | 1 | 0 | FDV | Fast Divide | Fd := Fn / Fm |
+| 1 | 0 | 1 | 1 | FRD | Fast reverse divide | Fd := Fm / Fn |
+| 1 | 1 | 0 | 0 | POL | Polar angle (ArcTan2) | Fd := arctan2(Fn,Fm) |
+| 1 | 1 | 0 | 1 | | undefined instruction | trap |
+| 1 | 1 | 1 | 0 | | undefined instruction | trap |
+| 1 | 1 | 1 | 1 | | undefined instruction | trap |
++---+---+---+---+----------+-----------------------+-----------------------+
+Note: POW, RPW, POL are deprecated, and are available for backwards
+ compatibility only.
+*/
+
+/*
+TABLE 4: Monadic Floating Point Opcodes
++---+---+---+---+----------+-----------------------+-----------------------+
+| a | b | c | d | Mnemonic | Description | Operation |
++---+---+---+---+----------+-----------------------+-----------------------+
+| 0 | 0 | 0 | 0 | MVF | Move | Fd := Fm |
+| 0 | 0 | 0 | 1 | MNF | Move negated | Fd := - Fm |
+| 0 | 0 | 1 | 0 | ABS | Absolute value | Fd := abs(Fm) |
+| 0 | 0 | 1 | 1 | RND | Round to integer | Fd := int(Fm) |
+| 0 | 1 | 0 | 0 | SQT | Square root | Fd := sqrt(Fm) |
+| 0 | 1 | 0 | 1 | LOG | Log base 10 | Fd := log10(Fm) |
+| 0 | 1 | 1 | 0 | LGN | Log base e | Fd := ln(Fm) |
+| 0 | 1 | 1 | 1 | EXP | Exponent | Fd := e ^ Fm |
+| 1 | 0 | 0 | 0 | SIN | Sine | Fd := sin(Fm) |
+| 1 | 0 | 0 | 1 | COS | Cosine | Fd := cos(Fm) |
+| 1 | 0 | 1 | 0 | TAN | Tangent | Fd := tan(Fm) |
+| 1 | 0 | 1 | 1 | ASN | Arc Sine | Fd := arcsin(Fm) |
+| 1 | 1 | 0 | 0 | ACS | Arc Cosine | Fd := arccos(Fm) |
+| 1 | 1 | 0 | 1 | ATN | Arc Tangent | Fd := arctan(Fm) |
+| 1 | 1 | 1 | 0 | URD | Unnormalized round | Fd := int(Fm) |
+| 1 | 1 | 1 | 1 | NRM | Normalize | Fd := norm(Fm) |
++---+---+---+---+----------+-----------------------+-----------------------+
+Note: LOG, LGN, EXP, SIN, COS, TAN, ASN, ACS, ATN are deprecated, and are
+ available for backwards compatibility only.
+*/
+
+/*
+TABLE 5
++-------------------------+---+---+
+| Rounding Precision | e | f |
++-------------------------+---+---+
+| IEEE Single precision | 0 ü 0 |
+| IEEE Double precision | 0 ü 1 |
+| IEEE Extended precision | 1 ü 0 |
+| undefined (trap) | 1 ü 1 |
++-------------------------+---+---+
+*/
+
+/*
+TABLE 5
++---------------------------------+---+---+
+| Rounding Mode | g | h |
++---------------------------------+---+---+
+| Round to nearest (default) | 0 ü 0 |
+| Round toward plus infinity | 0 ü 1 |
+| Round toward negative infinity | 1 ü 0 |
+| Round toward zero | 1 ü 1 |
++---------------------------------+---+---+
+*/
+
+/*
+===
+=== Definitions for load and store instructions
+===
+*/
+
+/* bit masks */
+#define BIT_PREINDEX 0x01000000
+#define BIT_UP 0x00800000
+#define BIT_WRITE_BACK 0x00200000
+#define BIT_LOAD 0x00100000
+
+/* masks for load/store */
+#define MASK_CPDT 0x0c000000 /* data processing opcode */
+#define MASK_OFFSET 0x000000ff
+#define MASK_TRANSFER_LENGTH 0x00408000
+#define MASK_REGISTER_COUNT MASK_TRANSFER_LENGTH
+#define MASK_COPROCESSOR 0x00000f00
+
+/* Tests for transfer length */
+#define TRANSFER_SINGLE 0x00000000
+#define TRANSFER_DOUBLE 0x00008000
+#define TRANSFER_EXTENDED 0x00400000
+#define TRANSFER_PACKED MASK_TRANSFER_LENGTH
+
+/* Get the coprocessor number from the opcode. */
+#define getCoprocessorNumber(opcode) ((opcode & MASK_COPROCESSOR) >> 8)
+
+/* Get the offset from the opcode. */
+#define getOffset(opcode) (opcode & MASK_OFFSET)
+
+/* Tests for specific data transfer load/store opcodes. */
+#define TEST_OPCODE(opcode,mask) (((opcode) & (mask)) == (mask))
+
+#define LOAD_OP(opcode) TEST_OPCODE((opcode),MASK_CPDT | BIT_LOAD)
+#define STORE_OP(opcode) ((opcode & (MASK_CPDT | BIT_LOAD)) == MASK_CPDT)
+
+#define LDF_OP(opcode) (LOAD_OP(opcode) && (getCoprocessorNumber(opcode) == 1))
+#define LFM_OP(opcode) (LOAD_OP(opcode) && (getCoprocessorNumber(opcode) == 2))
+#define STF_OP(opcode) (STORE_OP(opcode) && (getCoprocessorNumber(opcode) == 1))
+#define SFM_OP(opcode) (STORE_OP(opcode) && (getCoprocessorNumber(opcode) == 2))
+
+#define PREINDEXED(opcode) ((opcode & BIT_PREINDEX) != 0)
+#define POSTINDEXED(opcode) ((opcode & BIT_PREINDEX) == 0)
+#define BIT_UP_SET(opcode) ((opcode & BIT_UP) != 0)
+#define BIT_UP_CLEAR(opcode) ((opcode & BIT_DOWN) == 0)
+#define WRITE_BACK(opcode) ((opcode & BIT_WRITE_BACK) != 0)
+#define LOAD(opcode) ((opcode & BIT_LOAD) != 0)
+#define STORE(opcode) ((opcode & BIT_LOAD) == 0)
+
+/*
+===
+=== Definitions for arithmetic instructions
+===
+*/
+/* bit masks */
+#define BIT_MONADIC 0x00008000
+#define BIT_CONSTANT 0x00000008
+
+#define CONSTANT_FM(opcode) ((opcode & BIT_CONSTANT) != 0)
+#define MONADIC_INSTRUCTION(opcode) ((opcode & BIT_MONADIC) != 0)
+
+/* instruction identification masks */
+#define MASK_CPDO 0x0e000000 /* arithmetic opcode */
+#define MASK_ARITHMETIC_OPCODE 0x00f08000
+#define MASK_DESTINATION_SIZE 0x00080080
+
+/* dyadic arithmetic opcodes. */
+#define ADF_CODE 0x00000000
+#define MUF_CODE 0x00100000
+#define SUF_CODE 0x00200000
+#define RSF_CODE 0x00300000
+#define DVF_CODE 0x00400000
+#define RDF_CODE 0x00500000
+#define POW_CODE 0x00600000
+#define RPW_CODE 0x00700000
+#define RMF_CODE 0x00800000
+#define FML_CODE 0x00900000
+#define FDV_CODE 0x00a00000
+#define FRD_CODE 0x00b00000
+#define POL_CODE 0x00c00000
+/* 0x00d00000 is an invalid dyadic arithmetic opcode */
+/* 0x00e00000 is an invalid dyadic arithmetic opcode */
+/* 0x00f00000 is an invalid dyadic arithmetic opcode */
+
+/* monadic arithmetic opcodes. */
+#define MVF_CODE 0x00008000
+#define MNF_CODE 0x00108000
+#define ABS_CODE 0x00208000
+#define RND_CODE 0x00308000
+#define SQT_CODE 0x00408000
+#define LOG_CODE 0x00508000
+#define LGN_CODE 0x00608000
+#define EXP_CODE 0x00708000
+#define SIN_CODE 0x00808000
+#define COS_CODE 0x00908000
+#define TAN_CODE 0x00a08000
+#define ASN_CODE 0x00b08000
+#define ACS_CODE 0x00c08000
+#define ATN_CODE 0x00d08000
+#define URD_CODE 0x00e08000
+#define NRM_CODE 0x00f08000
+
+/*
+===
+=== Definitions for register transfer and comparison instructions
+===
+*/
+
+#define MASK_CPRT 0x0e000010 /* register transfer opcode */
+#define MASK_CPRT_CODE 0x00f00000
+#define FLT_CODE 0x00000000
+#define FIX_CODE 0x00100000
+#define WFS_CODE 0x00200000
+#define RFS_CODE 0x00300000
+#define WFC_CODE 0x00400000
+#define RFC_CODE 0x00500000
+#define CMF_CODE 0x00900000
+#define CNF_CODE 0x00b00000
+#define CMFE_CODE 0x00d00000
+#define CNFE_CODE 0x00f00000
+
+/*
+===
+=== Common definitions
+===
+*/
+
+/* register masks */
+#define MASK_Rd 0x0000f000
+#define MASK_Rn 0x000f0000
+#define MASK_Fd 0x00007000
+#define MASK_Fm 0x00000007
+#define MASK_Fn 0x00070000
+
+/* condition code masks */
+#define CC_MASK 0xf0000000
+#define CC_NEGATIVE 0x80000000
+#define CC_ZERO 0x40000000
+#define CC_CARRY 0x20000000
+#define CC_OVERFLOW 0x10000000
+#define CC_EQ 0x00000000
+#define CC_NE 0x10000000
+#define CC_CS 0x20000000
+#define CC_HS CC_CS
+#define CC_CC 0x30000000
+#define CC_LO CC_CC
+#define CC_MI 0x40000000
+#define CC_PL 0x50000000
+#define CC_VS 0x60000000
+#define CC_VC 0x70000000
+#define CC_HI 0x80000000
+#define CC_LS 0x90000000
+#define CC_GE 0xa0000000
+#define CC_LT 0xb0000000
+#define CC_GT 0xc0000000
+#define CC_LE 0xd0000000
+#define CC_AL 0xe0000000
+#define CC_NV 0xf0000000
+
+/* rounding masks/values */
+#define MASK_ROUNDING_MODE 0x00000060
+#define ROUND_TO_NEAREST 0x00000000
+#define ROUND_TO_PLUS_INFINITY 0x00000020
+#define ROUND_TO_MINUS_INFINITY 0x00000040
+#define ROUND_TO_ZERO 0x00000060
+
+#define MASK_ROUNDING_PRECISION 0x00080080
+#define ROUND_SINGLE 0x00000000
+#define ROUND_DOUBLE 0x00000080
+#define ROUND_EXTENDED 0x00080000
+
+/* Get the condition code from the opcode. */
+#define getCondition(opcode) (opcode >> 28)
+
+/* Get the source register from the opcode. */
+#define getRn(opcode) ((opcode & MASK_Rn) >> 16)
+
+/* Get the destination floating point register from the opcode. */
+#define getFd(opcode) ((opcode & MASK_Fd) >> 12)
+
+/* Get the first source floating point register from the opcode. */
+#define getFn(opcode) ((opcode & MASK_Fn) >> 16)
+
+/* Get the second source floating point register from the opcode. */
+#define getFm(opcode) (opcode & MASK_Fm)
+
+/* Get the destination register from the opcode. */
+#define getRd(opcode) ((opcode & MASK_Rd) >> 12)
+
+/* Get the rounding mode from the opcode. */
+#define getRoundingMode(opcode) ((opcode & MASK_ROUNDING_MODE) >> 5)
+
+float32 getSingleConstant(const unsigned int nIndex);
+float64 getDoubleConstant(const unsigned int nIndex);
+floatx80 getExtendedConstant(const unsigned int nIndex);
+
+unsigned int getRegisterCount(const unsigned int opcode);
+unsigned int getDestinationSize(const unsigned int opcode);
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/fpsr.h linux.ac/arch/arm/nwfpe/fpsr.h
--- linux.vanilla/arch/arm/nwfpe/fpsr.h Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/nwfpe/fpsr.h Tue Feb 2 20:59:49 1999
@@ -0,0 +1,108 @@
+/*
+ NetWinder Floating Point Emulator
+ (c) Corel Computer Corporation, 1998
+
+ Direct questions, comments to Scott Bambrough
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __FPSR_H__
+#define __FPSR_H__
+
+/*
+The FPSR is a 32 bit register consisting of 4 parts, each exactly
+one byte.
+
+ SYSTEM ID
+ EXCEPTION TRAP ENABLE BYTE
+ SYSTEM CONTROL BYTE
+ CUMULATIVE EXCEPTION FLAGS BYTE
+
+The FPCR is a 32 bit register consisting of bit flags.
+*/
+
+/* SYSTEM ID
+------------
+Note: the system id byte is read only */
+
+typedef unsigned int FPSR; /* type for floating point status register */
+typedef unsigned int FPCR; /* type for floating point control register */
+
+#define MASK_SYSID 0xff000000
+#define BIT_HARDWARE 0x80000000
+#define FP_EMULATOR 0x01000000 /* System ID for emulator */
+#define FP_ACCELERATOR 0x81000000 /* System ID for FPA11 */
+
+/* EXCEPTION TRAP ENABLE BYTE
+----------------------------- */
+
+#define MASK_TRAP_ENABLE 0x00ff0000
+#define MASK_TRAP_ENABLE_STRICT 0x001f0000
+#define BIT_IXE 0x00100000 /* inexact exception enable */
+#define BIT_UFE 0x00080000 /* underflow exception enable */
+#define BIT_OFE 0x00040000 /* overflow exception enable */
+#define BIT_DZE 0x00020000 /* divide by zero exception enable */
+#define BIT_IOE 0x00010000 /* invalid operation exception enable */
+
+/* SYSTEM CONTROL BYTE
+---------------------- */
+
+#define MASK_SYSTEM_CONTROL 0x0000ff00
+#define MASK_TRAP_STRICT 0x00001f00
+
+#define BIT_AC 0x00100000 /* use alternative C-flag definition
+ for compares */
+#define BIT_EP 0x00080000 /* use expanded packed decimal format */
+#define BIT_SO 0x00040000 /* select synchronous operation of FPA */
+#define BIT_NE 0x00020000 /* NaN exception bit */
+#define BIT_ND 0x00010000 /* no denormalized numbers bit */
+
+/* CUMULATIVE EXCEPTION FLAGS BYTE
+---------------------------------- */
+
+#define MASK_EXCEPTION_FLAGS 0x000000ff
+#define MASK_EXCEPTION_FLAGS_STRICT 0x0000001f
+
+#define BIT_IXC 0x00000010 /* inexact exception flag */
+#define BIT_UFC 0x00000008 /* underflow exception flag */
+#define BIT_OFC 0x00000004 /* overfloat exception flag */
+#define BIT_DZC 0x00000002 /* divide by zero exception flag */
+#define BIT_IOC 0x00000001 /* invalid operation exception flag */
+
+/* Floating Point Control Register
+----------------------------------*/
+
+#define BIT_RU 0x80000000 /* rounded up bit */
+#define BIT_IE 0x10000000 /* inexact bit */
+#define BIT_MO 0x08000000 /* mantissa overflow bit */
+#define BIT_EO 0x04000000 /* exponent overflow bit */
+#define BIT_SB 0x00000800 /* store bounce */
+#define BIT_AB 0x00000400 /* arithmetic bounce */
+#define BIT_RE 0x00000200 /* rounding exception */
+#define BIT_DA 0x00000100 /* disable FPA */
+
+#define MASK_OP 0x00f08010 /* AU operation code */
+#define MASK_PR 0x00080080 /* AU precision */
+#define MASK_S1 0x00070000 /* AU source register 1 */
+#define MASK_S2 0x00000007 /* AU source register 2 */
+#define MASK_DS 0x00007000 /* AU destination register */
+#define MASK_RM 0x00000060 /* AU rounding mode */
+#define MASK_ALU 0x9cfff2ff /* only ALU can write these bits */
+#define MASK_RESET 0x00000d00 /* bits set on reset, all others cleared */
+#define MASK_WFC MASK_RESET
+#define MASK_RFC ~MASK_RESET
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/milieu.h linux.ac/arch/arm/nwfpe/milieu.h
--- linux.vanilla/arch/arm/nwfpe/milieu.h Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/nwfpe/milieu.h Tue Feb 2 20:59:49 1999
@@ -0,0 +1,48 @@
+
+/*
+===============================================================================
+
+This C header file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/softfloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these three paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+Include common integer types and flags.
+-------------------------------------------------------------------------------
+*/
+#include "ARM-gcc.h"
+
+/*
+-------------------------------------------------------------------------------
+Symbolic Boolean literals.
+-------------------------------------------------------------------------------
+*/
+enum {
+ FALSE = 0,
+ TRUE = 1
+};
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/single_cpdo.c linux.ac/arch/arm/nwfpe/single_cpdo.c
--- linux.vanilla/arch/arm/nwfpe/single_cpdo.c Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/nwfpe/single_cpdo.c Tue Feb 2 20:59:49 1999
@@ -0,0 +1,256 @@
+/*
+ NetWinder Floating Point Emulator
+ (c) Corel Computer Corporation, 1998
+
+ Direct questions, comments to Scott Bambrough
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "config.h"
+#include "milieu.h"
+#include "softfloat.h"
+#include "fpopcode.h"
+#include "fpa11.h"
+
+float32 getSingleConstant(unsigned int);
+
+float32 float32_exp(float32 Fm);
+float32 float32_ln(float32 Fm);
+float32 float32_sin(float32 rFm);
+float32 float32_cos(float32 rFm);
+float32 float32_arcsin(float32 rFm);
+float32 float32_arctan(float32 rFm);
+float32 float32_log(float32 rFm);
+float32 float32_tan(float32 rFm);
+float32 float32_arccos(float32 rFm);
+float32 float32_pow(float32 rFn,float32 rFm);
+float32 float32_pol(float32 rFn,float32 rFm);
+
+unsigned int SingleCPDO(const unsigned int opcode)
+{
+ float32 rFm, rFn;
+ unsigned int Fd, Fm, Fn, nRc = 1;
+
+ //fp_printk("SingleCPDO(0x%08x)\n",opcode);
+
+ Fm = getFm(opcode);
+ if (CONSTANT_FM(opcode))
+ {
+ rFm = getSingleConstant(Fm);
+ //fp_printk("constant Fm = %d 0x%08x\n",Fm,rFm);
+ }
+ else
+ {
+ switch (fpa11->fpreg[Fm].fType)
+ {
+ case typeSingle:
+ rFm = fpa11->fpreg[Fm].fValue.fSingle;
+ break;
+
+ default: return 0;
+ }
+ }
+
+ if (!MONADIC_INSTRUCTION(opcode))
+ {
+ Fn = getFn(opcode);
+ switch (fpa11->fpreg[Fn].fType)
+ {
+ case typeSingle:
+ rFn = fpa11->fpreg[Fn].fValue.fSingle;
+ break;
+
+ default: return 0;
+ }
+ //fp_printk("dyadic instruction\n");
+ //fp_printk("Fn = %d, rFn = 0x%08x\n",Fn,rFn);
+ }
+
+ Fd = getFd(opcode);
+ switch (opcode & MASK_ARITHMETIC_OPCODE)
+ {
+ /* dyadic opcodes */
+ case ADF_CODE:
+ fpa11->fpreg[Fd].fValue.fSingle = float32_add(rFn,rFm);
+ break;
+
+ case MUF_CODE:
+ case FML_CODE:
+ fpa11->fpreg[Fd].fValue.fSingle = float32_mul(rFn,rFm);
+ break;
+
+ case SUF_CODE:
+ fpa11->fpreg[Fd].fValue.fSingle = float32_sub(rFn,rFm);
+ break;
+
+ case RSF_CODE:
+ fpa11->fpreg[Fd].fValue.fSingle = float32_sub(rFm,rFn);
+ break;
+
+ case DVF_CODE:
+ case FDV_CODE:
+ fpa11->fpreg[Fd].fValue.fSingle = float32_div(rFn,rFm);
+ break;
+
+ case RDF_CODE:
+ case FRD_CODE:
+ fpa11->fpreg[Fd].fValue.fSingle = float32_div(rFm,rFn);
+ break;
+
+ case POW_CODE:
+ fpa11->fpreg[Fd].fValue.fSingle = float32_pow(rFn,rFm);
+ break;
+
+ case RPW_CODE:
+ fpa11->fpreg[Fd].fValue.fSingle = float32_pow(rFm,rFn);
+ break;
+
+ case RMF_CODE:
+ fpa11->fpreg[Fd].fValue.fSingle = float32_rem(rFn,rFm);
+ break;
+
+ case POL_CODE:
+ fpa11->fpreg[Fd].fValue.fSingle = float32_pol(rFn,rFm);
+ break;
+
+ /* monadic opcodes */
+ case MVF_CODE:
+ fpa11->fpreg[Fd].fValue.fSingle = rFm;
+ break;
+
+ case MNF_CODE:
+ rFm ^= 0x80000000;
+ fpa11->fpreg[Fd].fValue.fSingle = rFm;
+ break;
+
+ case ABS_CODE:
+ rFm &= 0x7fffffff;
+ fpa11->fpreg[Fd].fValue.fSingle = rFm;
+ break;
+
+ case RND_CODE:
+ case URD_CODE:
+ fpa11->fpreg[Fd].fValue.fSingle =
+ int32_to_float32(float32_to_int32(rFm));
+ break;
+
+ case SQT_CODE:
+ fpa11->fpreg[Fd].fValue.fSingle = float32_sqrt(rFm);
+ break;
+
+ case LOG_CODE:
+ fpa11->fpreg[Fd].fValue.fSingle = float32_log(rFm);
+ break;
+
+ case LGN_CODE:
+ fpa11->fpreg[Fd].fValue.fSingle = float32_ln(rFm);
+ break;
+
+ case EXP_CODE:
+ fpa11->fpreg[Fd].fValue.fSingle = float32_exp(rFm);
+ break;
+
+ case SIN_CODE:
+ fpa11->fpreg[Fd].fValue.fSingle = float32_sin(rFm);
+ break;
+
+ case COS_CODE:
+ fpa11->fpreg[Fd].fValue.fSingle = float32_cos(rFm);
+ break;
+
+ case TAN_CODE:
+ fpa11->fpreg[Fd].fValue.fSingle = float32_tan(rFm);
+ break;
+
+ case ASN_CODE:
+ fpa11->fpreg[Fd].fValue.fSingle = float32_arcsin(rFm);
+ break;
+
+ case ACS_CODE:
+ fpa11->fpreg[Fd].fValue.fSingle = float32_arccos(rFm);
+ break;
+
+ case ATN_CODE:
+ fpa11->fpreg[Fd].fValue.fSingle = float32_arctan(rFm);
+ break;
+
+ case NRM_CODE:
+ break;
+
+ default:
+ {
+ nRc = 0;
+ }
+ }
+
+ if (0 != nRc) fpa11->fpreg[Fd].fType = typeSingle;
+ return nRc;
+}
+
+float32 float32_exp(float32 Fm)
+{
+//series
+}
+
+float32 float32_ln(float32 Fm)
+{
+//series
+}
+
+float32 float32_sin(float32 rFm)
+{
+//series
+}
+
+float32 float32_cos(float32 rFm)
+{
+//series
+}
+
+float32 float32_arcsin(float32 rFm)
+{
+//series
+}
+
+float32 float32_arctan(float32 rFm)
+{
+ //series
+}
+
+float32 float32_log(float32 rFm)
+{
+ return float32_div(float32_ln(rFm),getSingleConstant(7));
+}
+
+float32 float32_tan(float32 rFm)
+{
+ return float32_div(float32_sin(rFm),float32_cos(rFm));
+}
+
+float32 float32_arccos(float32 rFm)
+{
+ //return float32_sub(halfPi,float32_arcsin(rFm));
+}
+
+float32 float32_pow(float32 rFn,float32 rFm)
+{
+ return float32_exp(float32_mul(rFm,float32_ln(rFn)));
+}
+
+float32 float32_pol(float32 rFn,float32 rFm)
+{
+ return float32_arctan(float32_div(rFn,rFm));
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/softfloat-macros linux.ac/arch/arm/nwfpe/softfloat-macros
--- linux.vanilla/arch/arm/nwfpe/softfloat-macros Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/nwfpe/softfloat-macros Tue Feb 2 20:59:50 1999
@@ -0,0 +1,740 @@
+
+/*
+===============================================================================
+
+This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/softfloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these three paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+Shifts `a' right by the number of bits given in `count'. If any nonzero
+bits are shifted off, they are ``jammed'' into the least significant bit of
+the result by setting the least significant bit to 1. The value of `count'
+can be arbitrarily large; in particular, if `count' is greater than 32, the
+result will be either 0 or 1, depending on whether `a' is zero or nonzero.
+The result is stored in the location pointed to by `zPtr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr )
+{
+ bits32 z;
+ if ( count == 0 ) {
+ z = a;
+ }
+ else if ( count < 32 ) {
+ z = ( a>>count ) | ( ( a<<( ( - count ) & 31 ) ) != 0 );
+ }
+ else {
+ z = ( a != 0 );
+ }
+ *zPtr = z;
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts `a' right by the number of bits given in `count'. If any nonzero
+bits are shifted off, they are ``jammed'' into the least significant bit of
+the result by setting the least significant bit to 1. The value of `count'
+can be arbitrarily large; in particular, if `count' is greater than 64, the
+result will be either 0 or 1, depending on whether `a' is zero or nonzero.
+The result is stored in the location pointed to by `zPtr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void shift64RightJamming( bits64 a, int16 count, bits64 *zPtr )
+{
+ bits64 z;
+
+ __asm__("@shift64RightJamming -- start");
+ if ( count == 0 ) {
+ z = a;
+ }
+ else if ( count < 64 ) {
+ z = ( a>>count ) | ( ( a<<( ( - count ) & 63 ) ) != 0 );
+ }
+ else {
+ z = ( a != 0 );
+ }
+ __asm__("@shift64RightJamming -- end");
+ *zPtr = z;
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 128-bit value formed by concatenating `a0' and `a1' right by 64
+_plus_ the number of bits given in `count'. The shifted result is at most
+64 nonzero bits; this is stored at the location pointed to by `z0Ptr'. The
+bits shifted off form a second 64-bit result as follows: The _last_ bit
+shifted off is the most-significant bit of the extra result, and the other
+63 bits of the extra result are all zero if and only if _all_but_the_last_
+bits shifted off were all zero. This extra result is stored in the location
+pointed to by `z1Ptr'. The value of `count' can be arbitrarily large.
+ (This routine makes more sense if `a0' and `a1' are considered to form a
+fixed-point value with binary point between `a0' and `a1'. This fixed-point
+value is shifted right by the number of bits given in `count', and the
+integer part of the result is returned at the location pointed to by
+`z0Ptr'. The fractional part of the result may be slightly corrupted as
+described above, and is returned at the location pointed to by `z1Ptr'.)
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shift64ExtraRightJamming(
+ bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
+{
+ bits64 z0, z1;
+ int8 negCount = ( - count ) & 63;
+
+ if ( count == 0 ) {
+ z1 = a1;
+ z0 = a0;
+ }
+ else if ( count < 64 ) {
+ z1 = ( a0<>count;
+ }
+ else {
+ if ( count == 64 ) {
+ z1 = a0 | ( a1 != 0 );
+ }
+ else {
+ z1 = ( ( a0 | a1 ) != 0 );
+ }
+ z0 = 0;
+ }
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the
+number of bits given in `count'. Any bits shifted off are lost. The value
+of `count' can be arbitrarily large; in particular, if `count' is greater
+than 128, the result will be 0. The result is broken into two 64-bit pieces
+which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shift128Right(
+ bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
+{
+ bits64 z0, z1;
+ int8 negCount = ( - count ) & 63;
+
+ if ( count == 0 ) {
+ z1 = a1;
+ z0 = a0;
+ }
+ else if ( count < 64 ) {
+ z1 = ( a0<>count );
+ z0 = a0>>count;
+ }
+ else {
+ z1 = ( count < 64 ) ? ( a0>>( count & 63 ) ) : 0;
+ z0 = 0;
+ }
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the
+number of bits given in `count'. If any nonzero bits are shifted off, they
+are ``jammed'' into the least significant bit of the result by setting the
+least significant bit to 1. The value of `count' can be arbitrarily large;
+in particular, if `count' is greater than 128, the result will be either 0
+or 1, depending on whether the concatenation of `a0' and `a1' is zero or
+nonzero. The result is broken into two 64-bit pieces which are stored at
+the locations pointed to by `z0Ptr' and `z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shift128RightJamming(
+ bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
+{
+ bits64 z0, z1;
+ int8 negCount = ( - count ) & 63;
+
+ if ( count == 0 ) {
+ z1 = a1;
+ z0 = a0;
+ }
+ else if ( count < 64 ) {
+ z1 = ( a0<>count ) | ( ( a1<>count;
+ }
+ else {
+ if ( count == 64 ) {
+ z1 = a0 | ( a1 != 0 );
+ }
+ else if ( count < 128 ) {
+ z1 = ( a0>>( count & 63 ) ) | ( ( ( a0<>count );
+ z0 = a0>>count;
+ }
+ else {
+ if ( count == 64 ) {
+ z2 = a1;
+ z1 = a0;
+ }
+ else {
+ a2 |= a1;
+ if ( count < 128 ) {
+ z2 = a0<>( count & 63 );
+ }
+ else {
+ z2 = ( count == 128 ) ? a0 : ( a0 != 0 );
+ z1 = 0;
+ }
+ }
+ z0 = 0;
+ }
+ z2 |= ( a2 != 0 );
+ }
+ *z2Ptr = z2;
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 128-bit value formed by concatenating `a0' and `a1' left by the
+number of bits given in `count'. Any bits shifted off are lost. The value
+of `count' must be less than 64. The result is broken into two 64-bit
+pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shortShift128Left(
+ bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
+{
+
+ *z1Ptr = a1<>( ( - count ) & 63 ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' left
+by the number of bits given in `count'. Any bits shifted off are lost.
+The value of `count' must be less than 64. The result is broken into three
+64-bit pieces which are stored at the locations pointed to by `z0Ptr',
+`z1Ptr', and `z2Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shortShift192Left(
+ bits64 a0,
+ bits64 a1,
+ bits64 a2,
+ int16 count,
+ bits64 *z0Ptr,
+ bits64 *z1Ptr,
+ bits64 *z2Ptr
+ )
+{
+ bits64 z0, z1, z2;
+ int8 negCount;
+
+ z2 = a2<>negCount;
+ z0 |= a1>>negCount;
+ }
+ *z2Ptr = z2;
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Adds the 128-bit value formed by concatenating `a0' and `a1' to the 128-bit
+value formed by concatenating `b0' and `b1'. Addition is modulo 2^128, so
+any carry out is lost. The result is broken into two 64-bit pieces which
+are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ add128(
+ bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr )
+{
+ bits64 z1;
+
+ z1 = a1 + b1;
+ *z1Ptr = z1;
+ *z0Ptr = a0 + b0 + ( z1 < a1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Adds the 192-bit value formed by concatenating `a0', `a1', and `a2' to the
+192-bit value formed by concatenating `b0', `b1', and `b2'. Addition is
+modulo 2^192, so any carry out is lost. The result is broken into three
+64-bit pieces which are stored at the locations pointed to by `z0Ptr',
+`z1Ptr', and `z2Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ add192(
+ bits64 a0,
+ bits64 a1,
+ bits64 a2,
+ bits64 b0,
+ bits64 b1,
+ bits64 b2,
+ bits64 *z0Ptr,
+ bits64 *z1Ptr,
+ bits64 *z2Ptr
+ )
+{
+ bits64 z0, z1, z2;
+ int8 carry0, carry1;
+
+ z2 = a2 + b2;
+ carry1 = ( z2 < a2 );
+ z1 = a1 + b1;
+ carry0 = ( z1 < a1 );
+ z0 = a0 + b0;
+ z1 += carry1;
+ z0 += ( z1 < carry1 );
+ z0 += carry0;
+ *z2Ptr = z2;
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Subtracts the 128-bit value formed by concatenating `b0' and `b1' from the
+128-bit value formed by concatenating `a0' and `a1'. Subtraction is modulo
+2^128, so any borrow out (carry out) is lost. The result is broken into two
+64-bit pieces which are stored at the locations pointed to by `z0Ptr' and
+`z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ sub128(
+ bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr )
+{
+
+ *z1Ptr = a1 - b1;
+ *z0Ptr = a0 - b0 - ( a1 < b1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Subtracts the 192-bit value formed by concatenating `b0', `b1', and `b2'
+from the 192-bit value formed by concatenating `a0', `a1', and `a2'.
+Subtraction is modulo 2^192, so any borrow out (carry out) is lost. The
+result is broken into three 64-bit pieces which are stored at the locations
+pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ sub192(
+ bits64 a0,
+ bits64 a1,
+ bits64 a2,
+ bits64 b0,
+ bits64 b1,
+ bits64 b2,
+ bits64 *z0Ptr,
+ bits64 *z1Ptr,
+ bits64 *z2Ptr
+ )
+{
+ bits64 z0, z1, z2;
+ int8 borrow0, borrow1;
+
+ z2 = a2 - b2;
+ borrow1 = ( a2 < b2 );
+ z1 = a1 - b1;
+ borrow0 = ( a1 < b1 );
+ z0 = a0 - b0;
+ z0 -= ( z1 < borrow1 );
+ z1 -= borrow1;
+ z0 -= borrow0;
+ *z2Ptr = z2;
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Multiplies `a' by `b' to obtain a 128-bit product. The product is broken
+into two 64-bit pieces which are stored at the locations pointed to by
+`z0Ptr' and `z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void mul64To128( bits64 a, bits64 b, bits64 *z0Ptr, bits64 *z1Ptr )
+{
+ bits32 aHigh, aLow, bHigh, bLow;
+ bits64 z0, zMiddleA, zMiddleB, z1;
+
+ aLow = a;
+ aHigh = a>>32;
+ bLow = b;
+ bHigh = b>>32;
+ z1 = ( (bits64) aLow ) * bLow;
+ zMiddleA = ( (bits64) aLow ) * bHigh;
+ zMiddleB = ( (bits64) aHigh ) * bLow;
+ z0 = ( (bits64) aHigh ) * bHigh;
+ zMiddleA += zMiddleB;
+ z0 += ( ( (bits64) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 );
+ zMiddleA <<= 32;
+ z1 += zMiddleA;
+ z0 += ( z1 < zMiddleA );
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Multiplies the 128-bit value formed by concatenating `a0' and `a1' by `b' to
+obtain a 192-bit product. The product is broken into three 64-bit pieces
+which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and
+`z2Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ mul128By64To192(
+ bits64 a0,
+ bits64 a1,
+ bits64 b,
+ bits64 *z0Ptr,
+ bits64 *z1Ptr,
+ bits64 *z2Ptr
+ )
+{
+ bits64 z0, z1, z2, more1;
+
+ mul64To128( a1, b, &z1, &z2 );
+ mul64To128( a0, b, &z0, &more1 );
+ add128( z0, more1, 0, z1, &z0, &z1 );
+ *z2Ptr = z2;
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Multiplies the 128-bit value formed by concatenating `a0' and `a1' to the
+128-bit value formed by concatenating `b0' and `b1' to obtain a 256-bit
+product. The product is broken into four 64-bit pieces which are stored at
+the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ mul128To256(
+ bits64 a0,
+ bits64 a1,
+ bits64 b0,
+ bits64 b1,
+ bits64 *z0Ptr,
+ bits64 *z1Ptr,
+ bits64 *z2Ptr,
+ bits64 *z3Ptr
+ )
+{
+ bits64 z0, z1, z2, z3;
+ bits64 more1, more2;
+
+ mul64To128( a1, b1, &z2, &z3 );
+ mul64To128( a1, b0, &z1, &more2 );
+ add128( z1, more2, 0, z2, &z1, &z2 );
+ mul64To128( a0, b0, &z0, &more1 );
+ add128( z0, more1, 0, z1, &z0, &z1 );
+ mul64To128( a0, b1, &more1, &more2 );
+ add128( more1, more2, 0, z2, &more1, &z2 );
+ add128( z0, z1, 0, more1, &z0, &z1 );
+ *z3Ptr = z3;
+ *z2Ptr = z2;
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns an approximation to the 64-bit integer quotient obtained by dividing
+`b' into the 128-bit value formed by concatenating `a0' and `a1'. The
+divisor `b' must be at least 2^63. If q is the exact quotient truncated
+toward zero, the approximation returned lies between q and q + 2 inclusive.
+If the exact quotient q is larger than 64 bits, the maximum positive 64-bit
+unsigned integer is returned.
+-------------------------------------------------------------------------------
+*/
+static bits64 estimateDiv128To64( bits64 a0, bits64 a1, bits64 b )
+{
+ bits64 b0, b1;
+ bits64 rem0, rem1, term0, term1;
+ bits64 z;
+ if ( b <= a0 ) return LIT64( 0xFFFFFFFFFFFFFFFF );
+ b0 = b>>32;
+ z = ( b0<<32 <= a0 ) ? LIT64( 0xFFFFFFFF00000000 ) : ( a0 / b0 )<<32;
+ mul64To128( b, z, &term0, &term1 );
+ sub128( a0, a1, term0, term1, &rem0, &rem1 );
+ while ( ( (sbits64) rem0 ) < 0 ) {
+ z -= LIT64( 0x100000000 );
+ b1 = b<<32;
+ add128( rem0, rem1, b0, b1, &rem0, &rem1 );
+ }
+ rem0 = ( rem0<<32 ) | ( rem1>>32 );
+ z |= ( b0<<32 <= rem0 ) ? 0xFFFFFFFF : rem0 / b0;
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns an approximation to the square root of the 32-bit significand given
+by `a'. Considered as an integer, `a' must be at least 2^31. If bit 0 of
+`aExp' (the least significant bit) is 1, the integer returned approximates
+2^31*sqrt(`a'/2^31), where `a' is considered an integer. If bit 0 of `aExp'
+is 0, the integer returned approximates 2^31*sqrt(`a'/2^30). In either
+case, the approximation returned lies strictly within +/-2 of the exact
+value.
+-------------------------------------------------------------------------------
+*/
+static bits32 estimateSqrt32( int16 aExp, bits32 a )
+{
+ static const bits16 sqrtOddAdjustments[] = {
+ 0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0,
+ 0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67
+ };
+ static const bits16 sqrtEvenAdjustments[] = {
+ 0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E,
+ 0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002
+ };
+ int8 index;
+ bits32 z;
+
+ index = ( a>>27 ) & 15;
+ if ( aExp & 1 ) {
+ z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ index ];
+ z = ( ( a / z )<<14 ) + ( z<<15 );
+ a >>= 1;
+ }
+ else {
+ z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ index ];
+ z = a / z + z;
+ z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 );
+ if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 );
+ }
+ return ( (bits32) ( ( ( (bits64) a )<<31 ) / z ) ) + ( z>>1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the number of leading 0 bits before the most-significant 1 bit
+of `a'. If `a' is zero, 32 is returned.
+-------------------------------------------------------------------------------
+*/
+static int8 countLeadingZeros32( bits32 a )
+{
+ static const int8 countLeadingZerosHigh[] = {
+ 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ int8 shiftCount;
+
+ shiftCount = 0;
+ if ( a < 0x10000 ) {
+ shiftCount += 16;
+ a <<= 16;
+ }
+ if ( a < 0x1000000 ) {
+ shiftCount += 8;
+ a <<= 8;
+ }
+ shiftCount += countLeadingZerosHigh[ a>>24 ];
+ return shiftCount;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the number of leading 0 bits before the most-significant 1 bit
+of `a'. If `a' is zero, 64 is returned.
+-------------------------------------------------------------------------------
+*/
+static int8 countLeadingZeros64( bits64 a )
+{
+ int8 shiftCount;
+
+ shiftCount = 0;
+ if ( a < ( (bits64) 1 )<<32 ) {
+ shiftCount += 32;
+ }
+ else {
+ a >>= 32;
+ }
+ shiftCount += countLeadingZeros32( a );
+ return shiftCount;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the 128-bit value formed by concatenating `a0' and `a1'
+is equal to the 128-bit value formed by concatenating `b0' and `b1'.
+Otherwise, returns 0.
+-------------------------------------------------------------------------------
+*/
+INLINE flag eq128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
+{
+
+ return ( a0 == b0 ) && ( a1 == b1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less
+than or equal to the 128-bit value formed by concatenating `b0' and `b1'.
+Otherwise, returns 0.
+-------------------------------------------------------------------------------
+*/
+INLINE flag le128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
+{
+
+ return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less
+than the 128-bit value formed by concatenating `b0' and `b1'. Otherwise,
+returns 0.
+-------------------------------------------------------------------------------
+*/
+INLINE flag lt128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
+{
+
+ return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is
+not equal to the 128-bit value formed by concatenating `b0' and `b1'.
+Otherwise, returns 0.
+-------------------------------------------------------------------------------
+*/
+INLINE flag ne128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
+{
+
+ return ( a0 != b0 ) || ( a1 != b1 );
+
+}
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/softfloat-specialize linux.ac/arch/arm/nwfpe/softfloat-specialize
--- linux.vanilla/arch/arm/nwfpe/softfloat-specialize Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/nwfpe/softfloat-specialize Tue Feb 2 20:59:50 1999
@@ -0,0 +1,471 @@
+
+/*
+===============================================================================
+
+This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/softfloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these three paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+Underflow tininess-detection mode, statically initialized to default value.
+(The declaration in `softfloat.h' must match the `int8' type here.)
+-------------------------------------------------------------------------------
+*/
+int8 float_detect_tininess = float_tininess_after_rounding;
+
+/*
+-------------------------------------------------------------------------------
+Raises the exceptions specified by `flags'. Floating-point traps can be
+defined here if desired. It is currently not possible for such a trap to
+substitute a result value. If traps are not implemented, this routine
+should be simply `float_exception_flags |= flags;'.
+
+ScottB: November 4, 1998
+Moved this function out of softfloat-specialize into fpmodule.c.
+This effectively isolates all the changes required for integrating with the
+Linux kernel into fpmodule.c. Porting to NetBSD should only require modifying
+fpmodule.c to integrate with the NetBSD kernel (I hope!).
+-------------------------------------------------------------------------------
+void float_raise( int8 flags )
+{
+ float_exception_flags |= flags;
+}
+*/
+
+/*
+-------------------------------------------------------------------------------
+Internal canonical NaN format.
+-------------------------------------------------------------------------------
+*/
+typedef struct {
+ flag sign;
+ bits64 high, low;
+} commonNaNT;
+
+/*
+-------------------------------------------------------------------------------
+The pattern for a default generated single-precision NaN.
+-------------------------------------------------------------------------------
+*/
+#define float32_default_nan 0xFFFFFFFF
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is a NaN;
+otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag float32_is_nan( float32 a )
+{
+
+ return ( 0xFF000000 < (bits32) ( a<<1 ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is a signaling
+NaN; otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag float32_is_signaling_nan( float32 a )
+{
+
+ return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the single-precision floating-point NaN
+`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
+exception is raised.
+-------------------------------------------------------------------------------
+*/
+static commonNaNT float32ToCommonNaN( float32 a )
+{
+ commonNaNT z;
+
+ if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
+ z.sign = a>>31;
+ z.low = 0;
+ z.high = ( (bits64) a )<<41;
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the canonical NaN `a' to the single-
+precision floating-point format.
+-------------------------------------------------------------------------------
+*/
+static float32 commonNaNToFloat32( commonNaNT a )
+{
+
+ return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes two single-precision floating-point values `a' and `b', one of which
+is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
+signaling NaN, the invalid exception is raised.
+-------------------------------------------------------------------------------
+*/
+static float32 propagateFloat32NaN( float32 a, float32 b )
+{
+ flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+
+ aIsNaN = float32_is_nan( a );
+ aIsSignalingNaN = float32_is_signaling_nan( a );
+ bIsNaN = float32_is_nan( b );
+ bIsSignalingNaN = float32_is_signaling_nan( b );
+ a |= 0x00400000;
+ b |= 0x00400000;
+ if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
+ if ( aIsNaN ) {
+ return ( aIsSignalingNaN & bIsNaN ) ? b : a;
+ }
+ else {
+ return b;
+ }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+The pattern for a default generated double-precision NaN.
+-------------------------------------------------------------------------------
+*/
+#define float64_default_nan LIT64( 0xFFFFFFFFFFFFFFFF )
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is a NaN;
+otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag float64_is_nan( float64 a )
+{
+
+ return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is a signaling
+NaN; otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag float64_is_signaling_nan( float64 a )
+{
+
+ return
+ ( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
+ && ( a & LIT64( 0x0007FFFFFFFFFFFF ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the double-precision floating-point NaN
+`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
+exception is raised.
+-------------------------------------------------------------------------------
+*/
+static commonNaNT float64ToCommonNaN( float64 a )
+{
+ commonNaNT z;
+
+ if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
+ z.sign = a>>63;
+ z.low = 0;
+ z.high = a<<12;
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the canonical NaN `a' to the double-
+precision floating-point format.
+-------------------------------------------------------------------------------
+*/
+static float64 commonNaNToFloat64( commonNaNT a )
+{
+
+ return
+ ( ( (bits64) a.sign )<<63 )
+ | LIT64( 0x7FF8000000000000 )
+ | ( a.high>>12 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes two double-precision floating-point values `a' and `b', one of which
+is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
+signaling NaN, the invalid exception is raised.
+-------------------------------------------------------------------------------
+*/
+static float64 propagateFloat64NaN( float64 a, float64 b )
+{
+ flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+
+ aIsNaN = float64_is_nan( a );
+ aIsSignalingNaN = float64_is_signaling_nan( a );
+ bIsNaN = float64_is_nan( b );
+ bIsSignalingNaN = float64_is_signaling_nan( b );
+ a |= LIT64( 0x0008000000000000 );
+ b |= LIT64( 0x0008000000000000 );
+ if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
+ if ( aIsNaN ) {
+ return ( aIsSignalingNaN & bIsNaN ) ? b : a;
+ }
+ else {
+ return b;
+ }
+
+}
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+The pattern for a default generated extended double-precision NaN. The
+`high' and `low' values hold the most- and least-significant bits,
+respectively.
+-------------------------------------------------------------------------------
+*/
+#define floatx80_default_nan_high 0xFFFF
+#define floatx80_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF )
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the extended double-precision floating-point value `a' is a
+NaN; otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag floatx80_is_nan( floatx80 a )
+{
+
+ return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the extended double-precision floating-point value `a' is a
+signaling NaN; otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag floatx80_is_signaling_nan( floatx80 a )
+{
+ //register int lr;
+ bits64 aLow;
+
+ //__asm__("mov %0, lr" : : "g" (lr));
+ //fp_printk("floatx80_is_signalling_nan() called from 0x%08x\n",lr);
+ aLow = a.low & ~ LIT64( 0x4000000000000000 );
+ return
+ ( ( a.high & 0x7FFF ) == 0x7FFF )
+ && (bits64) ( aLow<<1 )
+ && ( a.low == aLow );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the extended double-precision floating-
+point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the
+invalid exception is raised.
+-------------------------------------------------------------------------------
+*/
+static commonNaNT floatx80ToCommonNaN( floatx80 a )
+{
+ commonNaNT z;
+
+ if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
+ z.sign = a.high>>15;
+ z.low = 0;
+ z.high = a.low<<1;
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the canonical NaN `a' to the extended
+double-precision floating-point format.
+-------------------------------------------------------------------------------
+*/
+static floatx80 commonNaNToFloatx80( commonNaNT a )
+{
+ floatx80 z;
+
+ z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 );
+ z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF;
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes two extended double-precision floating-point values `a' and `b', one
+of which is a NaN, and returns the appropriate NaN result. If either `a' or
+`b' is a signaling NaN, the invalid exception is raised.
+-------------------------------------------------------------------------------
+*/
+static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b )
+{
+ flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+
+ aIsNaN = floatx80_is_nan( a );
+ aIsSignalingNaN = floatx80_is_signaling_nan( a );
+ bIsNaN = floatx80_is_nan( b );
+ bIsSignalingNaN = floatx80_is_signaling_nan( b );
+ a.low |= LIT64( 0xC000000000000000 );
+ b.low |= LIT64( 0xC000000000000000 );
+ if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
+ if ( aIsNaN ) {
+ return ( aIsSignalingNaN & bIsNaN ) ? b : a;
+ }
+ else {
+ return b;
+ }
+
+}
+
+#endif
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+The pattern for a default generated quadruple-precision NaN. The `high' and
+`low' values hold the most- and least-significant bits, respectively.
+-------------------------------------------------------------------------------
+*/
+#define float128_default_nan_high LIT64( 0xFFFFFFFFFFFFFFFF )
+#define float128_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF )
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the quadruple-precision floating-point value `a' is a NaN;
+otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag float128_is_nan( float128 a )
+{
+
+ return
+ ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) )
+ && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the quadruple-precision floating-point value `a' is a
+signaling NaN; otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag float128_is_signaling_nan( float128 a )
+{
+
+ return
+ ( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE )
+ && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the quadruple-precision floating-point NaN
+`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
+exception is raised.
+-------------------------------------------------------------------------------
+*/
+static commonNaNT float128ToCommonNaN( float128 a )
+{
+ commonNaNT z;
+
+ if ( float128_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
+ z.sign = a.high>>63;
+ shortShift128Left( a.high, a.low, 16, &z.high, &z.low );
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the canonical NaN `a' to the quadruple-
+precision floating-point format.
+-------------------------------------------------------------------------------
+*/
+static float128 commonNaNToFloat128( commonNaNT a )
+{
+ float128 z;
+
+ shift128Right( a.high, a.low, 16, &z.high, &z.low );
+ z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF800000000000 );
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes two quadruple-precision floating-point values `a' and `b', one of
+which is a NaN, and returns the appropriate NaN result. If either `a' or
+`b' is a signaling NaN, the invalid exception is raised.
+-------------------------------------------------------------------------------
+*/
+static float128 propagateFloat128NaN( float128 a, float128 b )
+{
+ flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+
+ aIsNaN = float128_is_nan( a );
+ aIsSignalingNaN = float128_is_signaling_nan( a );
+ bIsNaN = float128_is_nan( b );
+ bIsSignalingNaN = float128_is_signaling_nan( b );
+ a.high |= LIT64( 0x0000800000000000 );
+ b.high |= LIT64( 0x0000800000000000 );
+ if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
+ if ( aIsNaN ) {
+ return ( aIsSignalingNaN & bIsNaN ) ? b : a;
+ }
+ else {
+ return b;
+ }
+
+}
+
+#endif
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/softfloat.c linux.ac/arch/arm/nwfpe/softfloat.c
--- linux.vanilla/arch/arm/nwfpe/softfloat.c Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/nwfpe/softfloat.c Tue Feb 2 20:59:50 1999
@@ -0,0 +1,4877 @@
+/*
+===============================================================================
+
+This C source file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/softfloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these three paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+#include "milieu.h"
+#include "softfloat.h"
+
+/*
+-------------------------------------------------------------------------------
+Floating-point rounding mode, extended double-precision rounding precision,
+and exception flags.
+-------------------------------------------------------------------------------
+*/
+int8 float_rounding_mode = float_round_nearest_even;
+int8 floatx80_rounding_precision = 80;
+int8 float_exception_flags = 0;
+
+/*
+-------------------------------------------------------------------------------
+Primitive arithmetic functions, including multi-word arithmetic, and
+division and square root approximations. (Can be specialized to target if
+desired.)
+-------------------------------------------------------------------------------
+*/
+#include "softfloat-macros"
+
+/*
+-------------------------------------------------------------------------------
+Functions and definitions to determine: (1) whether tininess for underflow
+is detected before or after rounding by default, (2) what (if anything)
+happens when exceptions are raised, (3) how signaling NaNs are distinguished
+from quiet NaNs, (4) the default generated quiet NaNs, and (5) how NaNs
+are propagated from function inputs to output. These details are target-
+specific.
+-------------------------------------------------------------------------------
+*/
+#include "softfloat-specialize"
+
+/*
+-------------------------------------------------------------------------------
+Takes a 64-bit fixed-point value `absZ' with binary point between bits 6
+and 7, and returns the properly rounded 32-bit integer corresponding to the
+input. If `zSign' is nonzero, the input is negated before being converted
+to an integer. Bit 63 of `absZ' must be zero. Ordinarily, the fixed-point
+input is simply rounded to an integer, with the inexact exception raised if
+the input cannot be represented exactly as an integer. If the fixed-point
+input is too large, however, the invalid exception is raised and the largest
+positive or negative integer is returned.
+-------------------------------------------------------------------------------
+*/
+static int32 roundAndPackInt32( flag zSign, bits64 absZ )
+{
+ int8 roundingMode;
+ flag roundNearestEven;
+ int8 roundIncrement, roundBits;
+ int32 z;
+
+ roundingMode = float_rounding_mode;
+ roundNearestEven = ( roundingMode == float_round_nearest_even );
+ roundIncrement = 0x40;
+ if ( ! roundNearestEven ) {
+ if ( roundingMode == float_round_to_zero ) {
+ roundIncrement = 0;
+ }
+ else {
+ roundIncrement = 0x7F;
+ if ( zSign ) {
+ if ( roundingMode == float_round_up ) roundIncrement = 0;
+ }
+ else {
+ if ( roundingMode == float_round_down ) roundIncrement = 0;
+ }
+ }
+ }
+ roundBits = absZ & 0x7F;
+ absZ = ( absZ + roundIncrement )>>7;
+ absZ &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven );
+ z = absZ;
+ if ( zSign ) z = - z;
+ if ( ( absZ>>32 ) || ( z && ( ( z < 0 ) ^ zSign ) ) ) {
+ float_exception_flags |= float_flag_invalid;
+ return zSign ? 0x80000000 : 0x7FFFFFFF;
+ }
+ if ( roundBits ) float_exception_flags |= float_flag_inexact;
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the fraction bits of the single-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE bits32 extractFloat32Frac( float32 a )
+{
+
+ return a & 0x007FFFFF;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the exponent bits of the single-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE int16 extractFloat32Exp( float32 a )
+{
+
+ return ( a>>23 ) & 0xFF;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the sign bit of the single-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE flag extractFloat32Sign( float32 a )
+{
+
+ return a>>31;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Normalizes the subnormal single-precision floating-point value represented
+by the denormalized significand `aSig'. The normalized exponent and
+significand are stored at the locations pointed to by `zExpPtr' and
+`zSigPtr', respectively.
+-------------------------------------------------------------------------------
+*/
+static void
+ normalizeFloat32Subnormal( bits32 aSig, int16 *zExpPtr, bits32 *zSigPtr )
+{
+ int8 shiftCount;
+
+ shiftCount = countLeadingZeros32( aSig ) - 8;
+ *zSigPtr = aSig<>7;
+ zSig &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven );
+ if ( zSig == 0 ) zExp = 0;
+ return packFloat32( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+and significand `zSig', and returns the proper single-precision floating-
+point value corresponding to the abstract input. This routine is just like
+`roundAndPackFloat32' except that `zSig' does not have to be normalized in
+any way. In all cases, `zExp' must be 1 less than the ``true'' floating-
+point exponent.
+-------------------------------------------------------------------------------
+*/
+static float32
+ normalizeRoundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig )
+{
+ int8 shiftCount;
+
+ shiftCount = countLeadingZeros32( zSig ) - 1;
+ return roundAndPackFloat32( zSign, zExp - shiftCount, zSig<>52 ) & 0x7FF;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the sign bit of the double-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE flag extractFloat64Sign( float64 a )
+{
+
+ return a>>63;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Normalizes the subnormal double-precision floating-point value represented
+by the denormalized significand `aSig'. The normalized exponent and
+significand are stored at the locations pointed to by `zExpPtr' and
+`zSigPtr', respectively.
+-------------------------------------------------------------------------------
+*/
+static void
+ normalizeFloat64Subnormal( bits64 aSig, int16 *zExpPtr, bits64 *zSigPtr )
+{
+ int8 shiftCount;
+
+ shiftCount = countLeadingZeros64( aSig ) - 11;
+ *zSigPtr = aSig<>10;
+ zSig &= ~ ( ( ( roundBits ^ 0x200 ) == 0 ) & roundNearestEven );
+ if ( zSig == 0 ) zExp = 0;
+ return packFloat64( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+and significand `zSig', and returns the proper double-precision floating-
+point value corresponding to the abstract input. This routine is just like
+`roundAndPackFloat64' except that `zSig' does not have to be normalized in
+any way. In all cases, `zExp' must be 1 less than the ``true'' floating-
+point exponent.
+-------------------------------------------------------------------------------
+*/
+static float64
+ normalizeRoundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig )
+{
+ int8 shiftCount;
+
+ shiftCount = countLeadingZeros64( zSig ) - 1;
+ return roundAndPackFloat64( zSign, zExp - shiftCount, zSig<>15;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Normalizes the subnormal extended double-precision floating-point value
+represented by the denormalized significand `aSig'. The normalized exponent
+and significand are stored at the locations pointed to by `zExpPtr' and
+`zSigPtr', respectively.
+-------------------------------------------------------------------------------
+*/
+static void
+ normalizeFloatx80Subnormal( bits64 aSig, int32 *zExpPtr, bits64 *zSigPtr )
+{
+ int8 shiftCount;
+
+ shiftCount = countLeadingZeros64( aSig );
+ *zSigPtr = aSig<>48 ) & 0x7FFF;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the sign bit of the quadruple-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE flag extractFloat128Sign( float128 a )
+{
+
+ return a.high>>63;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Normalizes the subnormal quadruple-precision floating-point value
+represented by the denormalized significand formed by the concatenation of
+`aSig0' and `aSig1'. The normalized exponent is stored at the location
+pointed to by `zExpPtr'. The most significant 49 bits of the normalized
+significand are stored at the location pointed to by `zSig0Ptr', and the
+least significant 64 bits of the normalized significand are stored at the
+location pointed to by `zSig1Ptr'.
+-------------------------------------------------------------------------------
+*/
+static void
+ normalizeFloat128Subnormal(
+ bits64 aSig0,
+ bits64 aSig1,
+ int32 *zExpPtr,
+ bits64 *zSig0Ptr,
+ bits64 *zSig1Ptr
+ )
+{
+ int8 shiftCount;
+
+ if ( aSig0 == 0 ) {
+ shiftCount = countLeadingZeros64( aSig1 ) - 15;
+ if ( shiftCount < 0 ) {
+ *zSig0Ptr = aSig1>>( - shiftCount );
+ *zSig1Ptr = aSig1<<( shiftCount & 63 );
+ }
+ else {
+ *zSig0Ptr = aSig1<>( - shiftCount );
+ if ( (bits32) ( aSig<<( shiftCount & 31 ) ) ) {
+ float_exception_flags |= float_flag_inexact;
+ }
+ return aSign ? - z : z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the single-precision floating-point value
+`a' to the double-precision floating-point format. The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float32_to_float64( float32 a )
+{
+ flag aSign;
+ int16 aExp;
+ bits32 aSig;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+ if ( aExp == 0xFF ) {
+ if ( aSig ) return commonNaNToFloat64( float32ToCommonNaN( a ) );
+ return packFloat64( aSign, 0x7FF, 0 );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return packFloat64( aSign, 0, 0 );
+ normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+ --aExp;
+ }
+ return packFloat64( aSign, aExp + 0x380, ( (bits64) aSig )<<29 );
+
+}
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the single-precision floating-point value
+`a' to the extended double-precision floating-point format. The conversion
+is performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 float32_to_floatx80( float32 a )
+{
+ flag aSign;
+ int16 aExp;
+ bits32 aSig;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+ if ( aExp == 0xFF ) {
+ if ( aSig ) return commonNaNToFloatx80( float32ToCommonNaN( a ) );
+ return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 );
+ normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+ }
+ aSig |= 0x00800000;
+ return packFloatx80( aSign, aExp + 0x3F80, ( (bits64) aSig )<<40 );
+
+}
+
+#endif
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the single-precision floating-point value
+`a' to the double-precision floating-point format. The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 float32_to_float128( float32 a )
+{
+ flag aSign;
+ int16 aExp;
+ bits32 aSig;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+ if ( aExp == 0xFF ) {
+ if ( aSig ) return commonNaNToFloat128( float32ToCommonNaN( a ) );
+ return packFloat128( aSign, 0x7FFF, 0, 0 );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 );
+ normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+ --aExp;
+ }
+ return packFloat128( aSign, aExp + 0x3F80, ( (bits64) aSig )<<25, 0 );
+
+}
+
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Rounds the single-precision floating-point value `a' to an integer, and
+returns the result as a single-precision floating-point value. The
+operation is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_round_to_int( float32 a )
+{
+ flag aSign;
+ int16 aExp;
+ bits32 lastBitMask, roundBitsMask;
+ int8 roundingMode;
+ float32 z;
+
+ aExp = extractFloat32Exp( a );
+ if ( 0x96 <= aExp ) {
+ if ( ( aExp == 0xFF ) && extractFloat32Frac( a ) ) {
+ return propagateFloat32NaN( a, a );
+ }
+ return a;
+ }
+ if ( aExp <= 0x7E ) {
+ if ( (bits32) ( a<<1 ) == 0 ) return a;
+ float_exception_flags |= float_flag_inexact;
+ aSign = extractFloat32Sign( a );
+ switch ( float_rounding_mode ) {
+ case float_round_nearest_even:
+ if ( ( aExp == 0x7E ) && extractFloat32Frac( a ) ) {
+ return packFloat32( aSign, 0x7F, 0 );
+ }
+ break;
+ case float_round_down:
+ return aSign ? 0xBF800000 : 0;
+ case float_round_up:
+ return aSign ? 0x80000000 : 0x3F800000;
+ }
+ return packFloat32( aSign, 0, 0 );
+ }
+ lastBitMask = 1;
+ lastBitMask <<= 0x96 - aExp;
+ roundBitsMask = lastBitMask - 1;
+ z = a;
+ roundingMode = float_rounding_mode;
+ if ( roundingMode == float_round_nearest_even ) {
+ z += lastBitMask>>1;
+ if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask;
+ }
+ else if ( roundingMode != float_round_to_zero ) {
+ if ( extractFloat32Sign( z ) ^ ( roundingMode == float_round_up ) ) {
+ z += roundBitsMask;
+ }
+ }
+ z &= ~ roundBitsMask;
+ if ( z != a ) float_exception_flags |= float_flag_inexact;
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the absolute values of the single-precision
+floating-point values `a' and `b'. If `zSign' is true, the sum is negated
+before being returned. `zSign' is ignored if the result is a NaN. The
+addition is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float32 addFloat32Sigs( float32 a, float32 b, flag zSign )
+{
+ int16 aExp, bExp, zExp;
+ bits32 aSig, bSig, zSig;
+ int16 expDiff;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ bSig = extractFloat32Frac( b );
+ bExp = extractFloat32Exp( b );
+ expDiff = aExp - bExp;
+ aSig <<= 6;
+ bSig <<= 6;
+ if ( 0 < expDiff ) {
+ if ( aExp == 0xFF ) {
+ if ( aSig ) return propagateFloat32NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) {
+ --expDiff;
+ }
+ else {
+ bSig |= 0x20000000;
+ }
+ shift32RightJamming( bSig, expDiff, &bSig );
+ zExp = aExp;
+ }
+ else if ( expDiff < 0 ) {
+ if ( bExp == 0xFF ) {
+ if ( bSig ) return propagateFloat32NaN( a, b );
+ return packFloat32( zSign, 0xFF, 0 );
+ }
+ if ( aExp == 0 ) {
+ ++expDiff;
+ }
+ else {
+ aSig |= 0x20000000;
+ }
+ shift32RightJamming( aSig, - expDiff, &aSig );
+ zExp = bExp;
+ }
+ else {
+ if ( aExp == 0xFF ) {
+ if ( aSig | bSig ) return propagateFloat32NaN( a, b );
+ return a;
+ }
+ if ( aExp == 0 ) return packFloat32( zSign, 0, ( aSig + bSig )>>6 );
+ zSig = 0x40000000 + aSig + bSig;
+ zExp = aExp;
+ goto roundAndPack;
+ }
+ aSig |= 0x20000000;
+ zSig = ( aSig + bSig )<<1;
+ --zExp;
+ if ( (sbits32) zSig < 0 ) {
+ zSig = aSig + bSig;
+ ++zExp;
+ }
+ roundAndPack:
+ return roundAndPackFloat32( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the absolute values of the single-
+precision floating-point values `a' and `b'. If `zSign' is true, the
+difference is negated before being returned. `zSign' is ignored if the
+result is a NaN. The subtraction is performed according to the IEC/IEEE
+Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float32 subFloat32Sigs( float32 a, float32 b, flag zSign )
+{
+ int16 aExp, bExp, zExp;
+ bits32 aSig, bSig, zSig;
+ int16 expDiff;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ bSig = extractFloat32Frac( b );
+ bExp = extractFloat32Exp( b );
+ expDiff = aExp - bExp;
+ aSig <<= 7;
+ bSig <<= 7;
+ if ( 0 < expDiff ) goto aExpBigger;
+ if ( expDiff < 0 ) goto bExpBigger;
+ if ( aExp == 0xFF ) {
+ if ( aSig | bSig ) return propagateFloat32NaN( a, b );
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ if ( aExp == 0 ) {
+ aExp = 1;
+ bExp = 1;
+ }
+ if ( bSig < aSig ) goto aBigger;
+ if ( aSig < bSig ) goto bBigger;
+ return packFloat32( float_rounding_mode == float_round_down, 0, 0 );
+ bExpBigger:
+ if ( bExp == 0xFF ) {
+ if ( bSig ) return propagateFloat32NaN( a, b );
+ return packFloat32( zSign ^ 1, 0xFF, 0 );
+ }
+ if ( aExp == 0 ) {
+ ++expDiff;
+ }
+ else {
+ aSig |= 0x40000000;
+ }
+ shift32RightJamming( aSig, - expDiff, &aSig );
+ bSig |= 0x40000000;
+ bBigger:
+ zSig = bSig - aSig;
+ zExp = bExp;
+ zSign ^= 1;
+ goto normalizeRoundAndPack;
+ aExpBigger:
+ if ( aExp == 0xFF ) {
+ if ( aSig ) return propagateFloat32NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) {
+ --expDiff;
+ }
+ else {
+ bSig |= 0x40000000;
+ }
+ shift32RightJamming( bSig, expDiff, &bSig );
+ aSig |= 0x40000000;
+ aBigger:
+ zSig = aSig - bSig;
+ zExp = aExp;
+ normalizeRoundAndPack:
+ --zExp;
+ return normalizeRoundAndPackFloat32( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the single-precision floating-point values `a'
+and `b'. The operation is performed according to the IEC/IEEE Standard for
+Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_add( float32 a, float32 b )
+{
+ flag aSign, bSign;
+
+ aSign = extractFloat32Sign( a );
+ bSign = extractFloat32Sign( b );
+ if ( aSign == bSign ) {
+ return addFloat32Sigs( a, b, aSign );
+ }
+ else {
+ return subFloat32Sigs( a, b, aSign );
+ }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the single-precision floating-point values
+`a' and `b'. The operation is performed according to the IEC/IEEE Standard
+for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_sub( float32 a, float32 b )
+{
+ flag aSign, bSign;
+
+ aSign = extractFloat32Sign( a );
+ bSign = extractFloat32Sign( b );
+ if ( aSign == bSign ) {
+ return subFloat32Sigs( a, b, aSign );
+ }
+ else {
+ return addFloat32Sigs( a, b, aSign );
+ }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of multiplying the single-precision floating-point values
+`a' and `b'. The operation is performed according to the IEC/IEEE Standard
+for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_mul( float32 a, float32 b )
+{
+ flag aSign, bSign, zSign;
+ int16 aExp, bExp, zExp;
+ bits32 aSig, bSig;
+ bits64 zSig64;
+ bits32 zSig;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+ bSig = extractFloat32Frac( b );
+ bExp = extractFloat32Exp( b );
+ bSign = extractFloat32Sign( b );
+ zSign = aSign ^ bSign;
+ if ( aExp == 0xFF ) {
+ if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) {
+ return propagateFloat32NaN( a, b );
+ }
+ if ( ( bExp | bSig ) == 0 ) {
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ return packFloat32( zSign, 0xFF, 0 );
+ }
+ if ( bExp == 0xFF ) {
+ if ( bSig ) return propagateFloat32NaN( a, b );
+ if ( ( aExp | aSig ) == 0 ) {
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ return packFloat32( zSign, 0xFF, 0 );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return packFloat32( zSign, 0, 0 );
+ normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+ }
+ if ( bExp == 0 ) {
+ if ( bSig == 0 ) return packFloat32( zSign, 0, 0 );
+ normalizeFloat32Subnormal( bSig, &bExp, &bSig );
+ }
+ zExp = aExp + bExp - 0x7F;
+ aSig = ( aSig | 0x00800000 )<<7;
+ bSig = ( bSig | 0x00800000 )<<8;
+ shift64RightJamming( ( (bits64) aSig ) * bSig, 32, &zSig64 );
+ zSig = zSig64;
+ if ( 0 <= (sbits32) ( zSig<<1 ) ) {
+ zSig <<= 1;
+ --zExp;
+ }
+ return roundAndPackFloat32( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of dividing the single-precision floating-point value `a'
+by the corresponding value `b'. The operation is performed according to the
+IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_div( float32 a, float32 b )
+{
+ flag aSign, bSign, zSign;
+ int16 aExp, bExp, zExp;
+ bits32 aSig, bSig, zSig;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+ bSig = extractFloat32Frac( b );
+ bExp = extractFloat32Exp( b );
+ bSign = extractFloat32Sign( b );
+ zSign = aSign ^ bSign;
+ if ( aExp == 0xFF ) {
+ if ( aSig ) return propagateFloat32NaN( a, b );
+ if ( bExp == 0xFF ) {
+ if ( bSig ) return propagateFloat32NaN( a, b );
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ return packFloat32( zSign, 0xFF, 0 );
+ }
+ if ( bExp == 0xFF ) {
+ if ( bSig ) return propagateFloat32NaN( a, b );
+ return packFloat32( zSign, 0, 0 );
+ }
+ if ( bExp == 0 ) {
+ if ( bSig == 0 ) {
+ if ( ( aExp | aSig ) == 0 ) {
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ float_raise( float_flag_divbyzero );
+ return packFloat32( zSign, 0xFF, 0 );
+ }
+ normalizeFloat32Subnormal( bSig, &bExp, &bSig );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return packFloat32( zSign, 0, 0 );
+ normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+ }
+ zExp = aExp - bExp + 0x7D;
+ aSig = ( aSig | 0x00800000 )<<7;
+ bSig = ( bSig | 0x00800000 )<<8;
+ if ( bSig <= ( aSig + aSig ) ) {
+ aSig >>= 1;
+ ++zExp;
+ }
+ zSig = ( ( (bits64) aSig )<<32 ) / bSig;
+ if ( ( zSig & 0x3F ) == 0 ) {
+ zSig |= ( ( (bits64) bSig ) * zSig != ( (bits64) aSig )<<32 );
+ }
+ return roundAndPackFloat32( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the remainder of the single-precision floating-point value `a'
+with respect to the corresponding value `b'. The operation is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_rem( float32 a, float32 b )
+{
+ flag aSign, bSign, zSign;
+ int16 aExp, bExp, expDiff;
+ bits32 aSig, bSig;
+ bits32 q;
+ bits64 aSig64, bSig64, q64;
+ bits32 alternateASig;
+ sbits32 sigMean;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+ bSig = extractFloat32Frac( b );
+ bExp = extractFloat32Exp( b );
+ bSign = extractFloat32Sign( b );
+ if ( aExp == 0xFF ) {
+ if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) {
+ return propagateFloat32NaN( a, b );
+ }
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ if ( bExp == 0xFF ) {
+ if ( bSig ) return propagateFloat32NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) {
+ if ( bSig == 0 ) {
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ normalizeFloat32Subnormal( bSig, &bExp, &bSig );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return a;
+ normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+ }
+ expDiff = aExp - bExp;
+ aSig |= 0x00800000;
+ bSig |= 0x00800000;
+ if ( expDiff < 32 ) {
+ aSig <<= 8;
+ bSig <<= 8;
+ if ( expDiff < 0 ) {
+ if ( expDiff < -1 ) return a;
+ aSig >>= 1;
+ }
+ q = ( bSig <= aSig );
+ if ( q ) aSig -= bSig;
+ if ( 0 < expDiff ) {
+ q = ( ( (bits64) aSig )<<32 ) / bSig;
+ q >>= 32 - expDiff;
+ bSig >>= 2;
+ aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q;
+ }
+ else {
+ aSig >>= 2;
+ bSig >>= 2;
+ }
+ }
+ else {
+ if ( bSig <= aSig ) aSig -= bSig;
+ aSig64 = ( (bits64) aSig )<<40;
+ bSig64 = ( (bits64) bSig )<<40;
+ expDiff -= 64;
+ while ( 0 < expDiff ) {
+ q64 = estimateDiv128To64( aSig64, 0, bSig64 );
+ q64 = ( 2 < q64 ) ? q64 - 2 : 0;
+ aSig64 = - ( ( bSig * q64 )<<38 );
+ expDiff -= 62;
+ }
+ expDiff += 64;
+ q64 = estimateDiv128To64( aSig64, 0, bSig64 );
+ q64 = ( 2 < q64 ) ? q64 - 2 : 0;
+ q = q64>>( 64 - expDiff );
+ bSig <<= 6;
+ aSig = ( ( aSig64>>33 )<<( expDiff - 1 ) ) - bSig * q;
+ }
+ do {
+ alternateASig = aSig;
+ ++q;
+ aSig -= bSig;
+ } while ( 0 <= (sbits32) aSig );
+ sigMean = aSig + alternateASig;
+ if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) {
+ aSig = alternateASig;
+ }
+ zSign = ( (sbits32) aSig < 0 );
+ if ( zSign ) aSig = - aSig;
+ return normalizeRoundAndPackFloat32( aSign ^ zSign, bExp, aSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the square root of the single-precision floating-point value `a'.
+The operation is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_sqrt( float32 a )
+{
+ flag aSign;
+ int16 aExp, zExp;
+ bits32 aSig, zSig;
+ bits64 rem, term;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+ if ( aExp == 0xFF ) {
+ if ( aSig ) return propagateFloat32NaN( a, 0 );
+ if ( ! aSign ) return a;
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ if ( aSign ) {
+ if ( ( aExp | aSig ) == 0 ) return a;
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return 0;
+ normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+ }
+ zExp = ( ( aExp - 0x7F )>>1 ) + 0x7E;
+ aSig = ( aSig | 0x00800000 )<<8;
+ zSig = estimateSqrt32( aExp, aSig ) + 2;
+ if ( ( zSig & 0x7F ) <= 5 ) {
+ if ( zSig < 2 ) {
+ zSig = 0xFFFFFFFF;
+ }
+ else {
+ aSig >>= aExp & 1;
+ term = ( (bits64) zSig ) * zSig;
+ rem = ( ( (bits64) aSig )<<32 ) - term;
+ while ( (sbits64) rem < 0 ) {
+ --zSig;
+ rem += ( ( (bits64) zSig )<<1 ) | 1;
+ }
+ zSig |= ( rem != 0 );
+ }
+ }
+ shift32RightJamming( zSig, 1, &zSig );
+ return roundAndPackFloat32( 0, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is equal to the
+corresponding value `b', and 0 otherwise. The comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_eq( float32 a, float32 b )
+{
+
+ if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+ || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+ ) {
+ if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is less than or
+equal to the corresponding value `b', and 0 otherwise. The comparison is
+performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_le( float32 a, float32 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+ || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ aSign = extractFloat32Sign( a );
+ bSign = extractFloat32Sign( b );
+ if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 );
+ return ( a == b ) || ( aSign ^ ( a < b ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is less than
+the corresponding value `b', and 0 otherwise. The comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_lt( float32 a, float32 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+ || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ aSign = extractFloat32Sign( a );
+ bSign = extractFloat32Sign( b );
+ if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 );
+ return ( a != b ) && ( aSign ^ ( a < b ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is equal to the
+corresponding value `b', and 0 otherwise. The invalid exception is raised
+if either operand is a NaN. Otherwise, the comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_eq_signaling( float32 a, float32 b )
+{
+
+ if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+ || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is less than or
+equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not
+cause an exception. Otherwise, the comparison is performed according to the
+IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_le_quiet( float32 a, float32 b )
+{
+ flag aSign, bSign;
+ //int16 aExp, bExp;
+
+ if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+ || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+ ) {
+ if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ aSign = extractFloat32Sign( a );
+ bSign = extractFloat32Sign( b );
+ if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 );
+ return ( a == b ) || ( aSign ^ ( a < b ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is less than
+the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an
+exception. Otherwise, the comparison is performed according to the IEC/IEEE
+Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_lt_quiet( float32 a, float32 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+ || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+ ) {
+ if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ aSign = extractFloat32Sign( a );
+ bSign = extractFloat32Sign( b );
+ if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 );
+ return ( a != b ) && ( aSign ^ ( a < b ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the double-precision floating-point value
+`a' to the 32-bit two's complement integer format. The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic---which means in particular that the conversion is rounded
+according to the current rounding mode. If `a' is a NaN, the largest
+positive integer is returned. Otherwise, if the conversion overflows, the
+largest integer with the same sign as `a' is returned.
+-------------------------------------------------------------------------------
+*/
+int32 float64_to_int32( float64 a )
+{
+ flag aSign;
+ int16 aExp, shiftCount;
+ bits64 aSig;
+
+ aSig = extractFloat64Frac( a );
+ aExp = extractFloat64Exp( a );
+ aSign = extractFloat64Sign( a );
+ if ( ( aExp == 0x7FF ) && aSig ) aSign = 0;
+ if ( aExp ) aSig |= LIT64( 0x0010000000000000 );
+ shiftCount = 0x42C - aExp;
+ if ( 0 < shiftCount ) shift64RightJamming( aSig, shiftCount, &aSig );
+ return roundAndPackInt32( aSign, aSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the double-precision floating-point value
+`a' to the 32-bit two's complement integer format. The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic, except that the conversion is always rounded toward zero. If
+`a' is a NaN, the largest positive integer is returned. Otherwise, if the
+conversion overflows, the largest integer with the same sign as `a' is
+returned.
+-------------------------------------------------------------------------------
+*/
+int32 float64_to_int32_round_to_zero( float64 a )
+{
+ flag aSign;
+ int16 aExp, shiftCount;
+ bits64 aSig, savedASig;
+ int32 z;
+
+ aSig = extractFloat64Frac( a );
+ aExp = extractFloat64Exp( a );
+ aSign = extractFloat64Sign( a );
+ shiftCount = 0x433 - aExp;
+ if ( shiftCount < 21 ) {
+ if ( ( aExp == 0x7FF ) && aSig ) aSign = 0;
+ goto invalid;
+ }
+ else if ( 52 < shiftCount ) {
+ if ( aExp || aSig ) float_exception_flags |= float_flag_inexact;
+ return 0;
+ }
+ aSig |= LIT64( 0x0010000000000000 );
+ savedASig = aSig;
+ aSig >>= shiftCount;
+ z = aSig;
+ if ( aSign ) z = - z;
+ if ( ( z < 0 ) ^ aSign ) {
+ invalid:
+ float_exception_flags |= float_flag_invalid;
+ return aSign ? 0x80000000 : 0x7FFFFFFF;
+ }
+ if ( ( aSig<>= shiftCount;
+ z = aSig;
+ if ( aSign ) z = - z;
+ if ( ( z < 0 ) ^ aSign ) {
+ invalid:
+ float_exception_flags |= float_flag_invalid;
+ return aSign ? 0x80000000 : 0x7FFFFFFF;
+ }
+ if ( ( aSig<>1;
+ if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask;
+ }
+ else if ( roundingMode != float_round_to_zero ) {
+ if ( extractFloat64Sign( z ) ^ ( roundingMode == float_round_up ) ) {
+ z += roundBitsMask;
+ }
+ }
+ z &= ~ roundBitsMask;
+ if ( z != a ) float_exception_flags |= float_flag_inexact;
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the absolute values of the double-precision
+floating-point values `a' and `b'. If `zSign' is true, the sum is negated
+before being returned. `zSign' is ignored if the result is a NaN. The
+addition is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float64 addFloat64Sigs( float64 a, float64 b, flag zSign )
+{
+ int16 aExp, bExp, zExp;
+ bits64 aSig, bSig, zSig;
+ int16 expDiff;
+
+ aSig = extractFloat64Frac( a );
+ aExp = extractFloat64Exp( a );
+ bSig = extractFloat64Frac( b );
+ bExp = extractFloat64Exp( b );
+ expDiff = aExp - bExp;
+ aSig <<= 9;
+ bSig <<= 9;
+ if ( 0 < expDiff ) {
+ if ( aExp == 0x7FF ) {
+ if ( aSig ) return propagateFloat64NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) {
+ --expDiff;
+ }
+ else {
+ bSig |= LIT64( 0x2000000000000000 );
+ }
+ shift64RightJamming( bSig, expDiff, &bSig );
+ zExp = aExp;
+ }
+ else if ( expDiff < 0 ) {
+ if ( bExp == 0x7FF ) {
+ if ( bSig ) return propagateFloat64NaN( a, b );
+ return packFloat64( zSign, 0x7FF, 0 );
+ }
+ if ( aExp == 0 ) {
+ ++expDiff;
+ }
+ else {
+ aSig |= LIT64( 0x2000000000000000 );
+ }
+ shift64RightJamming( aSig, - expDiff, &aSig );
+ zExp = bExp;
+ }
+ else {
+ if ( aExp == 0x7FF ) {
+ if ( aSig | bSig ) return propagateFloat64NaN( a, b );
+ return a;
+ }
+ if ( aExp == 0 ) return packFloat64( zSign, 0, ( aSig + bSig )>>9 );
+ zSig = LIT64( 0x4000000000000000 ) + aSig + bSig;
+ zExp = aExp;
+ goto roundAndPack;
+ }
+ aSig |= LIT64( 0x2000000000000000 );
+ zSig = ( aSig + bSig )<<1;
+ --zExp;
+ if ( (sbits64) zSig < 0 ) {
+ zSig = aSig + bSig;
+ ++zExp;
+ }
+ roundAndPack:
+ return roundAndPackFloat64( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the absolute values of the double-
+precision floating-point values `a' and `b'. If `zSign' is true, the
+difference is negated before being returned. `zSign' is ignored if the
+result is a NaN. The subtraction is performed according to the IEC/IEEE
+Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float64 subFloat64Sigs( float64 a, float64 b, flag zSign )
+{
+ int16 aExp, bExp, zExp;
+ bits64 aSig, bSig, zSig;
+ int16 expDiff;
+
+ aSig = extractFloat64Frac( a );
+ aExp = extractFloat64Exp( a );
+ bSig = extractFloat64Frac( b );
+ bExp = extractFloat64Exp( b );
+ expDiff = aExp - bExp;
+ aSig <<= 10;
+ bSig <<= 10;
+ if ( 0 < expDiff ) goto aExpBigger;
+ if ( expDiff < 0 ) goto bExpBigger;
+ if ( aExp == 0x7FF ) {
+ if ( aSig | bSig ) return propagateFloat64NaN( a, b );
+ float_raise( float_flag_invalid );
+ return float64_default_nan;
+ }
+ if ( aExp == 0 ) {
+ aExp = 1;
+ bExp = 1;
+ }
+ if ( bSig < aSig ) goto aBigger;
+ if ( aSig < bSig ) goto bBigger;
+ return packFloat64( float_rounding_mode == float_round_down, 0, 0 );
+ bExpBigger:
+ if ( bExp == 0x7FF ) {
+ if ( bSig ) return propagateFloat64NaN( a, b );
+ return packFloat64( zSign ^ 1, 0x7FF, 0 );
+ }
+ if ( aExp == 0 ) {
+ ++expDiff;
+ }
+ else {
+ aSig |= LIT64( 0x4000000000000000 );
+ }
+ shift64RightJamming( aSig, - expDiff, &aSig );
+ bSig |= LIT64( 0x4000000000000000 );
+ bBigger:
+ zSig = bSig - aSig;
+ zExp = bExp;
+ zSign ^= 1;
+ goto normalizeRoundAndPack;
+ aExpBigger:
+ if ( aExp == 0x7FF ) {
+ if ( aSig ) return propagateFloat64NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) {
+ --expDiff;
+ }
+ else {
+ bSig |= LIT64( 0x4000000000000000 );
+ }
+ shift64RightJamming( bSig, expDiff, &bSig );
+ aSig |= LIT64( 0x4000000000000000 );
+ aBigger:
+ zSig = aSig - bSig;
+ zExp = aExp;
+ normalizeRoundAndPack:
+ --zExp;
+ return normalizeRoundAndPackFloat64( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the double-precision floating-point values `a'
+and `b'. The operation is performed according to the IEC/IEEE Standard for
+Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_add( float64 a, float64 b )
+{
+ flag aSign, bSign;
+
+ aSign = extractFloat64Sign( a );
+ bSign = extractFloat64Sign( b );
+ if ( aSign == bSign ) {
+ return addFloat64Sigs( a, b, aSign );
+ }
+ else {
+ return subFloat64Sigs( a, b, aSign );
+ }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the double-precision floating-point values
+`a' and `b'. The operation is performed according to the IEC/IEEE Standard
+for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_sub( float64 a, float64 b )
+{
+ flag aSign, bSign;
+
+ aSign = extractFloat64Sign( a );
+ bSign = extractFloat64Sign( b );
+ if ( aSign == bSign ) {
+ return subFloat64Sigs( a, b, aSign );
+ }
+ else {
+ return addFloat64Sigs( a, b, aSign );
+ }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of multiplying the double-precision floating-point values
+`a' and `b'. The operation is performed according to the IEC/IEEE Standard
+for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_mul( float64 a, float64 b )
+{
+ flag aSign, bSign, zSign;
+ int16 aExp, bExp, zExp;
+ bits64 aSig, bSig, zSig0, zSig1;
+
+ aSig = extractFloat64Frac( a );
+ aExp = extractFloat64Exp( a );
+ aSign = extractFloat64Sign( a );
+ bSig = extractFloat64Frac( b );
+ bExp = extractFloat64Exp( b );
+ bSign = extractFloat64Sign( b );
+ zSign = aSign ^ bSign;
+ if ( aExp == 0x7FF ) {
+ if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) {
+ return propagateFloat64NaN( a, b );
+ }
+ if ( ( bExp | bSig ) == 0 ) {
+ float_raise( float_flag_invalid );
+ return float64_default_nan;
+ }
+ return packFloat64( zSign, 0x7FF, 0 );
+ }
+ if ( bExp == 0x7FF ) {
+ if ( bSig ) return propagateFloat64NaN( a, b );
+ if ( ( aExp | aSig ) == 0 ) {
+ float_raise( float_flag_invalid );
+ return float64_default_nan;
+ }
+ return packFloat64( zSign, 0x7FF, 0 );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return packFloat64( zSign, 0, 0 );
+ normalizeFloat64Subnormal( aSig, &aExp, &aSig );
+ }
+ if ( bExp == 0 ) {
+ if ( bSig == 0 ) return packFloat64( zSign, 0, 0 );
+ normalizeFloat64Subnormal( bSig, &bExp, &bSig );
+ }
+ zExp = aExp + bExp - 0x3FF;
+ aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10;
+ bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11;
+ mul64To128( aSig, bSig, &zSig0, &zSig1 );
+ zSig0 |= ( zSig1 != 0 );
+ if ( 0 <= (sbits64) ( zSig0<<1 ) ) {
+ zSig0 <<= 1;
+ --zExp;
+ }
+ return roundAndPackFloat64( zSign, zExp, zSig0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of dividing the double-precision floating-point value `a'
+by the corresponding value `b'. The operation is performed according to
+the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_div( float64 a, float64 b )
+{
+ flag aSign, bSign, zSign;
+ int16 aExp, bExp, zExp;
+ bits64 aSig, bSig, zSig;
+ bits64 rem0, rem1;
+ bits64 term0, term1;
+
+ aSig = extractFloat64Frac( a );
+ aExp = extractFloat64Exp( a );
+ aSign = extractFloat64Sign( a );
+ bSig = extractFloat64Frac( b );
+ bExp = extractFloat64Exp( b );
+ bSign = extractFloat64Sign( b );
+ zSign = aSign ^ bSign;
+ if ( aExp == 0x7FF ) {
+ if ( aSig ) return propagateFloat64NaN( a, b );
+ if ( bExp == 0x7FF ) {
+ if ( bSig ) return propagateFloat64NaN( a, b );
+ float_raise( float_flag_invalid );
+ return float64_default_nan;
+ }
+ return packFloat64( zSign, 0x7FF, 0 );
+ }
+ if ( bExp == 0x7FF ) {
+ if ( bSig ) return propagateFloat64NaN( a, b );
+ return packFloat64( zSign, 0, 0 );
+ }
+ if ( bExp == 0 ) {
+ if ( bSig == 0 ) {
+ if ( ( aExp | aSig ) == 0 ) {
+ float_raise( float_flag_invalid );
+ return float64_default_nan;
+ }
+ float_raise( float_flag_divbyzero );
+ return packFloat64( zSign, 0x7FF, 0 );
+ }
+ normalizeFloat64Subnormal( bSig, &bExp, &bSig );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return packFloat64( zSign, 0, 0 );
+ normalizeFloat64Subnormal( aSig, &aExp, &aSig );
+ }
+ zExp = aExp - bExp + 0x3FD;
+ aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10;
+ bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11;
+ if ( bSig <= ( aSig + aSig ) ) {
+ aSig >>= 1;
+ ++zExp;
+ }
+ zSig = estimateDiv128To64( aSig, 0, bSig );
+ if ( ( zSig & 0x1FF ) <= 2 ) {
+ mul64To128( bSig, zSig, &term0, &term1 );
+ sub128( aSig, 0, term0, term1, &rem0, &rem1 );
+ while ( (sbits64) rem0 < 0 ) {
+ --zSig;
+ add128( rem0, rem1, 0, bSig, &rem0, &rem1 );
+ }
+ zSig |= ( rem1 != 0 );
+ }
+ return roundAndPackFloat64( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the remainder of the double-precision floating-point value `a'
+with respect to the corresponding value `b'. The operation is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_rem( float64 a, float64 b )
+{
+ flag aSign, bSign, zSign;
+ int16 aExp, bExp, expDiff;
+ bits64 aSig, bSig;
+ bits64 q, alternateASig;
+ sbits64 sigMean;
+
+ aSig = extractFloat64Frac( a );
+ aExp = extractFloat64Exp( a );
+ aSign = extractFloat64Sign( a );
+ bSig = extractFloat64Frac( b );
+ bExp = extractFloat64Exp( b );
+ bSign = extractFloat64Sign( b );
+ if ( aExp == 0x7FF ) {
+ if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) {
+ return propagateFloat64NaN( a, b );
+ }
+ float_raise( float_flag_invalid );
+ return float64_default_nan;
+ }
+ if ( bExp == 0x7FF ) {
+ if ( bSig ) return propagateFloat64NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) {
+ if ( bSig == 0 ) {
+ float_raise( float_flag_invalid );
+ return float64_default_nan;
+ }
+ normalizeFloat64Subnormal( bSig, &bExp, &bSig );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return a;
+ normalizeFloat64Subnormal( aSig, &aExp, &aSig );
+ }
+ expDiff = aExp - bExp;
+ aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<11;
+ bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11;
+ if ( expDiff < 0 ) {
+ if ( expDiff < -1 ) return a;
+ aSig >>= 1;
+ }
+ q = ( bSig <= aSig );
+ if ( q ) aSig -= bSig;
+ expDiff -= 64;
+ while ( 0 < expDiff ) {
+ q = estimateDiv128To64( aSig, 0, bSig );
+ q = ( 2 < q ) ? q - 2 : 0;
+ aSig = - ( ( bSig>>2 ) * q );
+ expDiff -= 62;
+ }
+ expDiff += 64;
+ if ( 0 < expDiff ) {
+ q = estimateDiv128To64( aSig, 0, bSig );
+ q = ( 2 < q ) ? q - 2 : 0;
+ q >>= 64 - expDiff;
+ bSig >>= 2;
+ aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q;
+ }
+ else {
+ aSig >>= 2;
+ bSig >>= 2;
+ }
+ do {
+ alternateASig = aSig;
+ ++q;
+ aSig -= bSig;
+ } while ( 0 <= (sbits64) aSig );
+ sigMean = aSig + alternateASig;
+ if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) {
+ aSig = alternateASig;
+ }
+ zSign = ( (sbits64) aSig < 0 );
+ if ( zSign ) aSig = - aSig;
+ return normalizeRoundAndPackFloat64( aSign ^ zSign, bExp, aSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the square root of the double-precision floating-point value `a'.
+The operation is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_sqrt( float64 a )
+{
+ flag aSign;
+ int16 aExp, zExp;
+ bits64 aSig, zSig;
+ bits64 rem0, rem1, term0, term1; //, shiftedRem;
+ //float64 z;
+
+ aSig = extractFloat64Frac( a );
+ aExp = extractFloat64Exp( a );
+ aSign = extractFloat64Sign( a );
+ if ( aExp == 0x7FF ) {
+ if ( aSig ) return propagateFloat64NaN( a, a );
+ if ( ! aSign ) return a;
+ float_raise( float_flag_invalid );
+ return float64_default_nan;
+ }
+ if ( aSign ) {
+ if ( ( aExp | aSig ) == 0 ) return a;
+ float_raise( float_flag_invalid );
+ return float64_default_nan;
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return 0;
+ normalizeFloat64Subnormal( aSig, &aExp, &aSig );
+ }
+ zExp = ( ( aExp - 0x3FF )>>1 ) + 0x3FE;
+ aSig |= LIT64( 0x0010000000000000 );
+ zSig = estimateSqrt32( aExp, aSig>>21 );
+ zSig <<= 31;
+ aSig <<= 9 - ( aExp & 1 );
+ zSig = estimateDiv128To64( aSig, 0, zSig ) + zSig + 2;
+ if ( ( zSig & 0x3FF ) <= 5 ) {
+ if ( zSig < 2 ) {
+ zSig = LIT64( 0xFFFFFFFFFFFFFFFF );
+ }
+ else {
+ aSig <<= 2;
+ mul64To128( zSig, zSig, &term0, &term1 );
+ sub128( aSig, 0, term0, term1, &rem0, &rem1 );
+ while ( (sbits64) rem0 < 0 ) {
+ --zSig;
+ shortShift128Left( 0, zSig, 1, &term0, &term1 );
+ term1 |= 1;
+ add128( rem0, rem1, term0, term1, &rem0, &rem1 );
+ }
+ zSig |= ( ( rem0 | rem1 ) != 0 );
+ }
+ }
+ shift64RightJamming( zSig, 1, &zSig );
+ return roundAndPackFloat64( 0, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is equal to the
+corresponding value `b', and 0 otherwise. The comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float64_eq( float64 a, float64 b )
+{
+
+ if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+ || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+ ) {
+ if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is less than or
+equal to the corresponding value `b', and 0 otherwise. The comparison is
+performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float64_le( float64 a, float64 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+ || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ aSign = extractFloat64Sign( a );
+ bSign = extractFloat64Sign( b );
+ if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 );
+ return ( a == b ) || ( aSign ^ ( a < b ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is less than
+the corresponding value `b', and 0 otherwise. The comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float64_lt( float64 a, float64 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+ || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ aSign = extractFloat64Sign( a );
+ bSign = extractFloat64Sign( b );
+ if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 );
+ return ( a != b ) && ( aSign ^ ( a < b ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is equal to the
+corresponding value `b', and 0 otherwise. The invalid exception is raised
+if either operand is a NaN. Otherwise, the comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float64_eq_signaling( float64 a, float64 b )
+{
+
+ if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+ || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is less than or
+equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not
+cause an exception. Otherwise, the comparison is performed according to the
+IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float64_le_quiet( float64 a, float64 b )
+{
+ flag aSign, bSign;
+ //int16 aExp, bExp;
+
+ if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+ || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+ ) {
+ if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ aSign = extractFloat64Sign( a );
+ bSign = extractFloat64Sign( b );
+ if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 );
+ return ( a == b ) || ( aSign ^ ( a < b ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is less than
+the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an
+exception. Otherwise, the comparison is performed according to the IEC/IEEE
+Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float64_lt_quiet( float64 a, float64 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+ || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+ ) {
+ if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ aSign = extractFloat64Sign( a );
+ bSign = extractFloat64Sign( b );
+ if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 );
+ return ( a != b ) && ( aSign ^ ( a < b ) );
+
+}
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the extended double-precision floating-
+point value `a' to the 32-bit two's complement integer format. The
+conversion is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic---which means in particular that the conversion
+is rounded according to the current rounding mode. If `a' is a NaN, the
+largest positive integer is returned. Otherwise, if the conversion
+overflows, the largest integer with the same sign as `a' is returned.
+-------------------------------------------------------------------------------
+*/
+int32 floatx80_to_int32( floatx80 a )
+{
+ flag aSign;
+ int32 aExp, shiftCount;
+ bits64 aSig;
+
+ aSig = extractFloatx80Frac( a );
+ aExp = extractFloatx80Exp( a );
+ aSign = extractFloatx80Sign( a );
+ if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0;
+ shiftCount = 0x4037 - aExp;
+ if ( shiftCount <= 0 ) shiftCount = 1;
+ shift64RightJamming( aSig, shiftCount, &aSig );
+ return roundAndPackInt32( aSign, aSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the extended double-precision floating-
+point value `a' to the 32-bit two's complement integer format. The
+conversion is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic, except that the conversion is always rounded
+toward zero. If `a' is a NaN, the largest positive integer is returned.
+Otherwise, if the conversion overflows, the largest integer with the same
+sign as `a' is returned.
+-------------------------------------------------------------------------------
+*/
+int32 floatx80_to_int32_round_to_zero( floatx80 a )
+{
+ flag aSign;
+ int32 aExp, shiftCount;
+ bits64 aSig, savedASig;
+ int32 z;
+
+ aSig = extractFloatx80Frac( a );
+ aExp = extractFloatx80Exp( a );
+ aSign = extractFloatx80Sign( a );
+ shiftCount = 0x403E - aExp;
+ if ( shiftCount < 32 ) {
+ if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0;
+ goto invalid;
+ }
+ else if ( 63 < shiftCount ) {
+ if ( aExp || aSig ) float_exception_flags |= float_flag_inexact;
+ return 0;
+ }
+ savedASig = aSig;
+ aSig >>= shiftCount;
+ z = aSig;
+ if ( aSign ) z = - z;
+ if ( ( z < 0 ) ^ aSign ) {
+ invalid:
+ float_exception_flags |= float_flag_invalid;
+ return aSign ? 0x80000000 : 0x7FFFFFFF;
+ }
+ if ( ( aSig<>1;
+ if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask;
+ }
+ else if ( roundingMode != float_round_to_zero ) {
+ if ( extractFloatx80Sign( z ) ^ ( roundingMode == float_round_up ) ) {
+ z.low += roundBitsMask;
+ }
+ }
+ z.low &= ~ roundBitsMask;
+ if ( z.low == 0 ) {
+ ++z.high;
+ z.low = LIT64( 0x8000000000000000 );
+ }
+ if ( z.low != a.low ) float_exception_flags |= float_flag_inexact;
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the absolute values of the extended double-
+precision floating-point values `a' and `b'. If `zSign' is true, the sum is
+negated before being returned. `zSign' is ignored if the result is a NaN.
+The addition is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign )
+{
+ int32 aExp, bExp, zExp;
+ bits64 aSig, bSig, zSig0, zSig1;
+ int32 expDiff;
+
+ aSig = extractFloatx80Frac( a );
+ aExp = extractFloatx80Exp( a );
+ bSig = extractFloatx80Frac( b );
+ bExp = extractFloatx80Exp( b );
+ expDiff = aExp - bExp;
+ if ( 0 < expDiff ) {
+ if ( aExp == 0x7FFF ) {
+ if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) --expDiff;
+ shift64ExtraRightJamming( bSig, 0, expDiff, &bSig, &zSig1 );
+ zExp = aExp;
+ }
+ else if ( expDiff < 0 ) {
+ if ( bExp == 0x7FFF ) {
+ if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b );
+ return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ }
+ if ( aExp == 0 ) ++expDiff;
+ shift64ExtraRightJamming( aSig, 0, - expDiff, &aSig, &zSig1 );
+ zExp = bExp;
+ }
+ else {
+ if ( aExp == 0x7FFF ) {
+ if ( (bits64) ( ( aSig | bSig )<<1 ) ) {
+ return propagateFloatx80NaN( a, b );
+ }
+ return a;
+ }
+ zSig1 = 0;
+ zSig0 = aSig + bSig;
+ if ( aExp == 0 ) {
+ normalizeFloatx80Subnormal( zSig0, &zExp, &zSig0 );
+ goto roundAndPack;
+ }
+ zExp = aExp;
+ goto shiftRight1;
+ }
+
+ zSig0 = aSig + bSig;
+
+ if ( (sbits64) zSig0 < 0 ) goto roundAndPack;
+ shiftRight1:
+ shift64ExtraRightJamming( zSig0, zSig1, 1, &zSig0, &zSig1 );
+ zSig0 |= LIT64( 0x8000000000000000 );
+ ++zExp;
+ roundAndPack:
+ return
+ roundAndPackFloatx80(
+ floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the absolute values of the extended
+double-precision floating-point values `a' and `b'. If `zSign' is true,
+the difference is negated before being returned. `zSign' is ignored if the
+result is a NaN. The subtraction is performed according to the IEC/IEEE
+Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static floatx80 subFloatx80Sigs( floatx80 a, floatx80 b, flag zSign )
+{
+ int32 aExp, bExp, zExp;
+ bits64 aSig, bSig, zSig0, zSig1;
+ int32 expDiff;
+ floatx80 z;
+
+ aSig = extractFloatx80Frac( a );
+ aExp = extractFloatx80Exp( a );
+ bSig = extractFloatx80Frac( b );
+ bExp = extractFloatx80Exp( b );
+ expDiff = aExp - bExp;
+ if ( 0 < expDiff ) goto aExpBigger;
+ if ( expDiff < 0 ) goto bExpBigger;
+ if ( aExp == 0x7FFF ) {
+ if ( (bits64) ( ( aSig | bSig )<<1 ) ) {
+ return propagateFloatx80NaN( a, b );
+ }
+ float_raise( float_flag_invalid );
+ z.low = floatx80_default_nan_low;
+ z.high = floatx80_default_nan_high;
+ return z;
+ }
+ if ( aExp == 0 ) {
+ aExp = 1;
+ bExp = 1;
+ }
+ zSig1 = 0;
+ if ( bSig < aSig ) goto aBigger;
+ if ( aSig < bSig ) goto bBigger;
+ return packFloatx80( float_rounding_mode == float_round_down, 0, 0 );
+ bExpBigger:
+ if ( bExp == 0x7FFF ) {
+ if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b );
+ return packFloatx80( zSign ^ 1, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ }
+ if ( aExp == 0 ) ++expDiff;
+ shift128RightJamming( aSig, 0, - expDiff, &aSig, &zSig1 );
+ bBigger:
+ sub128( bSig, 0, aSig, zSig1, &zSig0, &zSig1 );
+ zExp = bExp;
+ zSign ^= 1;
+ goto normalizeRoundAndPack;
+ aExpBigger:
+ if ( aExp == 0x7FFF ) {
+ if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) --expDiff;
+ shift128RightJamming( bSig, 0, expDiff, &bSig, &zSig1 );
+ aBigger:
+ sub128( aSig, 0, bSig, zSig1, &zSig0, &zSig1 );
+ zExp = aExp;
+ normalizeRoundAndPack:
+ return
+ normalizeRoundAndPackFloatx80(
+ floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the extended double-precision floating-point
+values `a' and `b'. The operation is performed according to the IEC/IEEE
+Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_add( floatx80 a, floatx80 b )
+{
+ flag aSign, bSign;
+
+ aSign = extractFloatx80Sign( a );
+ bSign = extractFloatx80Sign( b );
+ if ( aSign == bSign ) {
+ return addFloatx80Sigs( a, b, aSign );
+ }
+ else {
+ return subFloatx80Sigs( a, b, aSign );
+ }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the extended double-precision floating-
+point values `a' and `b'. The operation is performed according to the
+IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_sub( floatx80 a, floatx80 b )
+{
+ flag aSign, bSign;
+
+ aSign = extractFloatx80Sign( a );
+ bSign = extractFloatx80Sign( b );
+ if ( aSign == bSign ) {
+ return subFloatx80Sigs( a, b, aSign );
+ }
+ else {
+ return addFloatx80Sigs( a, b, aSign );
+ }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of multiplying the extended double-precision floating-
+point values `a' and `b'. The operation is performed according to the
+IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_mul( floatx80 a, floatx80 b )
+{
+ flag aSign, bSign, zSign;
+ int32 aExp, bExp, zExp;
+ bits64 aSig, bSig, zSig0, zSig1;
+ floatx80 z;
+
+ aSig = extractFloatx80Frac( a );
+ aExp = extractFloatx80Exp( a );
+ aSign = extractFloatx80Sign( a );
+ bSig = extractFloatx80Frac( b );
+ bExp = extractFloatx80Exp( b );
+ bSign = extractFloatx80Sign( b );
+ zSign = aSign ^ bSign;
+ if ( aExp == 0x7FFF ) {
+ if ( (bits64) ( aSig<<1 )
+ || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) {
+ return propagateFloatx80NaN( a, b );
+ }
+ if ( ( bExp | bSig ) == 0 ) goto invalid;
+ return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ }
+ if ( bExp == 0x7FFF ) {
+ if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b );
+ if ( ( aExp | aSig ) == 0 ) {
+ invalid:
+ float_raise( float_flag_invalid );
+ z.low = floatx80_default_nan_low;
+ z.high = floatx80_default_nan_high;
+ return z;
+ }
+ return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 );
+ normalizeFloatx80Subnormal( aSig, &aExp, &aSig );
+ }
+ if ( bExp == 0 ) {
+ if ( bSig == 0 ) return packFloatx80( zSign, 0, 0 );
+ normalizeFloatx80Subnormal( bSig, &bExp, &bSig );
+ }
+ zExp = aExp + bExp - 0x3FFE;
+ mul64To128( aSig, bSig, &zSig0, &zSig1 );
+ if ( 0 < (sbits64) zSig0 ) {
+ shortShift128Left( zSig0, zSig1, 1, &zSig0, &zSig1 );
+ --zExp;
+ }
+ return
+ roundAndPackFloatx80(
+ floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of dividing the extended double-precision floating-point
+value `a' by the corresponding value `b'. The operation is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_div( floatx80 a, floatx80 b )
+{
+ flag aSign, bSign, zSign;
+ int32 aExp, bExp, zExp;
+ bits64 aSig, bSig, zSig0, zSig1;
+ bits64 rem0, rem1, rem2, term0, term1, term2;
+ floatx80 z;
+
+ aSig = extractFloatx80Frac( a );
+ aExp = extractFloatx80Exp( a );
+ aSign = extractFloatx80Sign( a );
+ bSig = extractFloatx80Frac( b );
+ bExp = extractFloatx80Exp( b );
+ bSign = extractFloatx80Sign( b );
+ zSign = aSign ^ bSign;
+ if ( aExp == 0x7FFF ) {
+ if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b );
+ if ( bExp == 0x7FFF ) {
+ if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b );
+ goto invalid;
+ }
+ return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ }
+ if ( bExp == 0x7FFF ) {
+ if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b );
+ return packFloatx80( zSign, 0, 0 );
+ }
+ if ( bExp == 0 ) {
+ if ( bSig == 0 ) {
+ if ( ( aExp | aSig ) == 0 ) {
+ invalid:
+ float_raise( float_flag_invalid );
+ z.low = floatx80_default_nan_low;
+ z.high = floatx80_default_nan_high;
+ return z;
+ }
+ float_raise( float_flag_divbyzero );
+ return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ }
+ normalizeFloatx80Subnormal( bSig, &bExp, &bSig );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 );
+ normalizeFloatx80Subnormal( aSig, &aExp, &aSig );
+ }
+ zExp = aExp - bExp + 0x3FFE;
+ rem1 = 0;
+ if ( bSig <= aSig ) {
+ shift128Right( aSig, 0, 1, &aSig, &rem1 );
+ ++zExp;
+ }
+ zSig0 = estimateDiv128To64( aSig, rem1, bSig );
+ mul64To128( bSig, zSig0, &term0, &term1 );
+ sub128( aSig, rem1, term0, term1, &rem0, &rem1 );
+ while ( (sbits64) rem0 < 0 ) {
+ --zSig0;
+ add128( rem0, rem1, 0, bSig, &rem0, &rem1 );
+ }
+ zSig1 = estimateDiv128To64( rem1, 0, bSig );
+ if ( (bits64) ( zSig1<<1 ) <= 8 ) {
+ mul64To128( bSig, zSig1, &term1, &term2 );
+ sub128( rem1, 0, term1, term2, &rem1, &rem2 );
+ while ( (sbits64) rem1 < 0 ) {
+ --zSig1;
+ add128( rem1, rem2, 0, bSig, &rem1, &rem2 );
+ }
+ zSig1 |= ( ( rem1 | rem2 ) != 0 );
+ }
+ return
+ roundAndPackFloatx80(
+ floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the remainder of the extended double-precision floating-point value
+`a' with respect to the corresponding value `b'. The operation is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_rem( floatx80 a, floatx80 b )
+{
+ flag aSign, bSign, zSign;
+ int32 aExp, bExp, expDiff;
+ bits64 aSig0, aSig1, bSig;
+ bits64 q, term0, term1, alternateASig0, alternateASig1;
+ floatx80 z;
+
+ aSig0 = extractFloatx80Frac( a );
+ aExp = extractFloatx80Exp( a );
+ aSign = extractFloatx80Sign( a );
+ bSig = extractFloatx80Frac( b );
+ bExp = extractFloatx80Exp( b );
+ bSign = extractFloatx80Sign( b );
+ if ( aExp == 0x7FFF ) {
+ if ( (bits64) ( aSig0<<1 )
+ || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) {
+ return propagateFloatx80NaN( a, b );
+ }
+ goto invalid;
+ }
+ if ( bExp == 0x7FFF ) {
+ if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) {
+ if ( bSig == 0 ) {
+ invalid:
+ float_raise( float_flag_invalid );
+ z.low = floatx80_default_nan_low;
+ z.high = floatx80_default_nan_high;
+ return z;
+ }
+ normalizeFloatx80Subnormal( bSig, &bExp, &bSig );
+ }
+ if ( aExp == 0 ) {
+ if ( (bits64) ( aSig0<<1 ) == 0 ) return a;
+ normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 );
+ }
+ bSig |= LIT64( 0x8000000000000000 );
+ zSign = aSign;
+ expDiff = aExp - bExp;
+ aSig1 = 0;
+ if ( expDiff < 0 ) {
+ if ( expDiff < -1 ) return a;
+ shift128Right( aSig0, 0, 1, &aSig0, &aSig1 );
+ expDiff = 0;
+ }
+ q = ( bSig <= aSig0 );
+ if ( q ) aSig0 -= bSig;
+ expDiff -= 64;
+ while ( 0 < expDiff ) {
+ q = estimateDiv128To64( aSig0, aSig1, bSig );
+ q = ( 2 < q ) ? q - 2 : 0;
+ mul64To128( bSig, q, &term0, &term1 );
+ sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 );
+ shortShift128Left( aSig0, aSig1, 62, &aSig0, &aSig1 );
+ expDiff -= 62;
+ }
+ expDiff += 64;
+ if ( 0 < expDiff ) {
+ q = estimateDiv128To64( aSig0, aSig1, bSig );
+ q = ( 2 < q ) ? q - 2 : 0;
+ q >>= 64 - expDiff;
+ mul64To128( bSig, q<<( 64 - expDiff ), &term0, &term1 );
+ sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 );
+ shortShift128Left( 0, bSig, 64 - expDiff, &term0, &term1 );
+ while ( le128( term0, term1, aSig0, aSig1 ) ) {
+ ++q;
+ sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 );
+ }
+ }
+ else {
+ term1 = 0;
+ term0 = bSig;
+ }
+ sub128( term0, term1, aSig0, aSig1, &alternateASig0, &alternateASig1 );
+ if ( lt128( alternateASig0, alternateASig1, aSig0, aSig1 )
+ || ( eq128( alternateASig0, alternateASig1, aSig0, aSig1 )
+ && ( q & 1 ) )
+ ) {
+ aSig0 = alternateASig0;
+ aSig1 = alternateASig1;
+ zSign = ! zSign;
+ }
+ return
+ normalizeRoundAndPackFloatx80(
+ 80, zSign, bExp + expDiff, aSig0, aSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the square root of the extended double-precision floating-point
+value `a'. The operation is performed according to the IEC/IEEE Standard
+for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_sqrt( floatx80 a )
+{
+ flag aSign;
+ int32 aExp, zExp;
+ bits64 aSig0, aSig1, zSig0, zSig1;
+ bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
+ bits64 shiftedRem0, shiftedRem1;
+ floatx80 z;
+
+ aSig0 = extractFloatx80Frac( a );
+ aExp = extractFloatx80Exp( a );
+ aSign = extractFloatx80Sign( a );
+ if ( aExp == 0x7FFF ) {
+ if ( (bits64) ( aSig0<<1 ) ) return propagateFloatx80NaN( a, a );
+ if ( ! aSign ) return a;
+ goto invalid;
+ }
+ if ( aSign ) {
+ if ( ( aExp | aSig0 ) == 0 ) return a;
+ invalid:
+ float_raise( float_flag_invalid );
+ z.low = floatx80_default_nan_low;
+ z.high = floatx80_default_nan_high;
+ return z;
+ }
+ if ( aExp == 0 ) {
+ if ( aSig0 == 0 ) return packFloatx80( 0, 0, 0 );
+ normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 );
+ }
+ zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFF;
+ zSig0 = estimateSqrt32( aExp, aSig0>>32 );
+ zSig0 <<= 31;
+ aSig1 = 0;
+ shift128Right( aSig0, 0, ( aExp & 1 ) + 2, &aSig0, &aSig1 );
+ zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0 ) + zSig0 + 4;
+ if ( 0 <= (sbits64) zSig0 ) zSig0 = LIT64( 0xFFFFFFFFFFFFFFFF );
+ shortShift128Left( aSig0, aSig1, 2, &aSig0, &aSig1 );
+ mul64To128( zSig0, zSig0, &term0, &term1 );
+ sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 );
+ while ( (sbits64) rem0 < 0 ) {
+ --zSig0;
+ shortShift128Left( 0, zSig0, 1, &term0, &term1 );
+ term1 |= 1;
+ add128( rem0, rem1, term0, term1, &rem0, &rem1 );
+ }
+ shortShift128Left( rem0, rem1, 63, &shiftedRem0, &shiftedRem1 );
+ zSig1 = estimateDiv128To64( shiftedRem0, shiftedRem1, zSig0 );
+ if ( (bits64) ( zSig1<<1 ) <= 10 ) {
+ if ( zSig1 == 0 ) zSig1 = 1;
+ mul64To128( zSig0, zSig1, &term1, &term2 );
+ shortShift128Left( term1, term2, 1, &term1, &term2 );
+ sub128( rem1, 0, term1, term2, &rem1, &rem2 );
+ mul64To128( zSig1, zSig1, &term2, &term3 );
+ sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 );
+ while ( (sbits64) rem1 < 0 ) {
+ --zSig1;
+ shortShift192Left( 0, zSig0, zSig1, 1, &term1, &term2, &term3 );
+ term3 |= 1;
+ add192(
+ rem1, rem2, rem3, term1, term2, term3, &rem1, &rem2, &rem3 );
+ }
+ zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
+ }
+ return
+ roundAndPackFloatx80(
+ floatx80_rounding_precision, 0, zExp, zSig0, zSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the extended double-precision floating-point value `a' is
+equal to the corresponding value `b', and 0 otherwise. The comparison is
+performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag floatx80_eq( floatx80 a, floatx80 b )
+{
+
+ if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
+ && (bits64) ( extractFloatx80Frac( a )<<1 ) )
+ || ( ( extractFloatx80Exp( b ) == 0x7FFF )
+ && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+ ) {
+ if ( floatx80_is_signaling_nan( a )
+ || floatx80_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ return
+ ( a.low == b.low )
+ && ( ( a.high == b.high )
+ || ( ( a.low == 0 )
+ && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) )
+ );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the extended double-precision floating-point value `a' is
+less than or equal to the corresponding value `b', and 0 otherwise. The
+comparison is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag floatx80_le( floatx80 a, floatx80 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
+ && (bits64) ( extractFloatx80Frac( a )<<1 ) )
+ || ( ( extractFloatx80Exp( b ) == 0x7FFF )
+ && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ aSign = extractFloatx80Sign( a );
+ bSign = extractFloatx80Sign( b );
+ if ( aSign != bSign ) {
+ return
+ aSign
+ || ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+ == 0 );
+ }
+ return
+ aSign ? le128( b.high, b.low, a.high, a.low )
+ : le128( a.high, a.low, b.high, b.low );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the extended double-precision floating-point value `a' is
+less than the corresponding value `b', and 0 otherwise. The comparison
+is performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag floatx80_lt( floatx80 a, floatx80 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
+ && (bits64) ( extractFloatx80Frac( a )<<1 ) )
+ || ( ( extractFloatx80Exp( b ) == 0x7FFF )
+ && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ aSign = extractFloatx80Sign( a );
+ bSign = extractFloatx80Sign( b );
+ if ( aSign != bSign ) {
+ return
+ aSign
+ && ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+ != 0 );
+ }
+ return
+ aSign ? lt128( b.high, b.low, a.high, a.low )
+ : lt128( a.high, a.low, b.high, b.low );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the extended double-precision floating-point value `a' is equal
+to the corresponding value `b', and 0 otherwise. The invalid exception is
+raised if either operand is a NaN. Otherwise, the comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag floatx80_eq_signaling( floatx80 a, floatx80 b )
+{
+
+ if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
+ && (bits64) ( extractFloatx80Frac( a )<<1 ) )
+ || ( ( extractFloatx80Exp( b ) == 0x7FFF )
+ && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ return
+ ( a.low == b.low )
+ && ( ( a.high == b.high )
+ || ( ( a.low == 0 )
+ && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) )
+ );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the extended double-precision floating-point value `a' is less
+than or equal to the corresponding value `b', and 0 otherwise. Quiet NaNs
+do not cause an exception. Otherwise, the comparison is performed according
+to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag floatx80_le_quiet( floatx80 a, floatx80 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
+ && (bits64) ( extractFloatx80Frac( a )<<1 ) )
+ || ( ( extractFloatx80Exp( b ) == 0x7FFF )
+ && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+ ) {
+ if ( floatx80_is_signaling_nan( a )
+ || floatx80_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ aSign = extractFloatx80Sign( a );
+ bSign = extractFloatx80Sign( b );
+ if ( aSign != bSign ) {
+ return
+ aSign
+ || ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+ == 0 );
+ }
+ return
+ aSign ? le128( b.high, b.low, a.high, a.low )
+ : le128( a.high, a.low, b.high, b.low );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the extended double-precision floating-point value `a' is less
+than the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause
+an exception. Otherwise, the comparison is performed according to the
+IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag floatx80_lt_quiet( floatx80 a, floatx80 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
+ && (bits64) ( extractFloatx80Frac( a )<<1 ) )
+ || ( ( extractFloatx80Exp( b ) == 0x7FFF )
+ && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+ ) {
+ if ( floatx80_is_signaling_nan( a )
+ || floatx80_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ aSign = extractFloatx80Sign( a );
+ bSign = extractFloatx80Sign( b );
+ if ( aSign != bSign ) {
+ return
+ aSign
+ && ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+ != 0 );
+ }
+ return
+ aSign ? lt128( b.high, b.low, a.high, a.low )
+ : lt128( a.high, a.low, b.high, b.low );
+
+}
+
+#endif
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the quadruple-precision floating-point
+value `a' to the 32-bit two's complement integer format. The conversion
+is performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic---which means in particular that the conversion is rounded
+according to the current rounding mode. If `a' is a NaN, the largest
+positive integer is returned. Otherwise, if the conversion overflows, the
+largest integer with the same sign as `a' is returned.
+-------------------------------------------------------------------------------
+*/
+int32 float128_to_int32( float128 a )
+{
+ flag aSign;
+ int32 aExp, shiftCount;
+ bits64 aSig0, aSig1;
+
+ aSig1 = extractFloat128Frac1( a );
+ aSig0 = extractFloat128Frac0( a );
+ aExp = extractFloat128Exp( a );
+ aSign = extractFloat128Sign( a );
+ if ( ( aExp == 0x7FFF ) && ( aSig0 | aSig1 ) ) aSign = 0;
+ if ( aExp ) aSig0 |= LIT64( 0x0001000000000000 );
+ aSig0 |= ( aSig1 != 0 );
+ shiftCount = 0x4028 - aExp;
+ if ( 0 < shiftCount ) shift64RightJamming( aSig0, shiftCount, &aSig0 );
+ return roundAndPackInt32( aSign, aSig0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the quadruple-precision floating-point
+value `a' to the 32-bit two's complement integer format. The conversion
+is performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic, except that the conversion is always rounded toward zero. If
+`a' is a NaN, the largest positive integer is returned. Otherwise, if the
+conversion overflows, the largest integer with the same sign as `a' is
+returned.
+-------------------------------------------------------------------------------
+*/
+int32 float128_to_int32_round_to_zero( float128 a )
+{
+ flag aSign;
+ int32 aExp, shiftCount;
+ bits64 aSig0, aSig1, savedASig;
+ int32 z;
+
+ aSig1 = extractFloat128Frac1( a );
+ aSig0 = extractFloat128Frac0( a );
+ aExp = extractFloat128Exp( a );
+ aSign = extractFloat128Sign( a );
+ aSig0 |= ( aSig1 != 0 );
+ shiftCount = 0x402F - aExp;
+ if ( shiftCount < 17 ) {
+ if ( ( aExp == 0x7FFF ) && aSig0 ) aSign = 0;
+ goto invalid;
+ }
+ else if ( 48 < shiftCount ) {
+ if ( aExp || aSig0 ) float_exception_flags |= float_flag_inexact;
+ return 0;
+ }
+ aSig0 |= LIT64( 0x0001000000000000 );
+ savedASig = aSig0;
+ aSig0 >>= shiftCount;
+ z = aSig0;
+ if ( aSign ) z = - z;
+ if ( ( z < 0 ) ^ aSign ) {
+ invalid:
+ float_exception_flags |= float_flag_invalid;
+ return aSign ? 0x80000000 : 0x7FFFFFFF;
+ }
+ if ( ( aSig0<>1, &z.high, &z.low );
+ if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask;
+ }
+ else {
+ if ( (sbits64) z.low < 0 ) {
+ ++z.high;
+ if ( (bits64) ( z.low<<1 ) == 0 ) z.high &= ~1;
+ }
+ }
+ }
+ else if ( roundingMode != float_round_to_zero ) {
+ if ( extractFloat128Sign( z )
+ ^ ( roundingMode == float_round_up ) ) {
+ add128( z.high, z.low, 0, roundBitsMask, &z.high, &z.low );
+ }
+ }
+ z.low &= ~ roundBitsMask;
+ }
+ else {
+ if ( aExp <= 0x3FFE ) {
+ if ( ( ( (bits64) ( a.high<<1 ) ) | a.low ) == 0 ) return a;
+ float_exception_flags |= float_flag_inexact;
+ aSign = extractFloat128Sign( a );
+ switch ( float_rounding_mode ) {
+ case float_round_nearest_even:
+ if ( ( aExp == 0x3FFE )
+ && ( extractFloat128Frac0( a )
+ | extractFloat128Frac1( a ) )
+ ) {
+ return packFloat128( aSign, 0x3FFF, 0, 0 );
+ }
+ break;
+ case float_round_down:
+ return
+ aSign ? packFloat128( 1, 0x3FFF, 0, 0 )
+ : packFloat128( 0, 0, 0, 0 );
+ case float_round_up:
+ return
+ aSign ? packFloat128( 1, 0, 0, 0 )
+ : packFloat128( 0, 0x3FFF, 0, 0 );
+ }
+ return packFloat128( aSign, 0, 0, 0 );
+ }
+ lastBitMask = 1;
+ lastBitMask <<= 0x402F - aExp;
+ roundBitsMask = lastBitMask - 1;
+ z.low = 0;
+ z.high = a.high;
+ roundingMode = float_rounding_mode;
+ if ( roundingMode == float_round_nearest_even ) {
+ z.high += lastBitMask>>1;
+ if ( ( ( z.high & roundBitsMask ) | a.low ) == 0 ) {
+ z.high &= ~ lastBitMask;
+ }
+ }
+ else if ( roundingMode != float_round_to_zero ) {
+ if ( extractFloat128Sign( z )
+ ^ ( roundingMode == float_round_up ) ) {
+ z.high |= ( a.low != 0 );
+ z.high += roundBitsMask;
+ }
+ }
+ z.high &= ~ roundBitsMask;
+ }
+ if ( ( z.low != a.low ) || ( z.high != a.high ) ) {
+ float_exception_flags |= float_flag_inexact;
+ }
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the absolute values of the quadruple-precision
+floating-point values `a' and `b'. If `zSign' is true, the sum is negated
+before being returned. `zSign' is ignored if the result is a NaN. The
+addition is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float128 addFloat128Sigs( float128 a, float128 b, flag zSign )
+{
+ int32 aExp, bExp, zExp;
+ bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
+ int32 expDiff;
+
+ aSig1 = extractFloat128Frac1( a );
+ aSig0 = extractFloat128Frac0( a );
+ aExp = extractFloat128Exp( a );
+ bSig1 = extractFloat128Frac1( b );
+ bSig0 = extractFloat128Frac0( b );
+ bExp = extractFloat128Exp( b );
+ expDiff = aExp - bExp;
+ if ( 0 < expDiff ) {
+ if ( aExp == 0x7FFF ) {
+ if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) {
+ --expDiff;
+ }
+ else {
+ bSig0 |= LIT64( 0x0001000000000000 );
+ }
+ shift128ExtraRightJamming(
+ bSig0, bSig1, 0, expDiff, &bSig0, &bSig1, &zSig2 );
+ zExp = aExp;
+ }
+ else if ( expDiff < 0 ) {
+ if ( bExp == 0x7FFF ) {
+ if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
+ return packFloat128( zSign, 0x7FFF, 0, 0 );
+ }
+ if ( aExp == 0 ) {
+ ++expDiff;
+ }
+ else {
+ aSig0 |= LIT64( 0x0001000000000000 );
+ }
+ shift128ExtraRightJamming(
+ aSig0, aSig1, 0, - expDiff, &aSig0, &aSig1, &zSig2 );
+ zExp = bExp;
+ }
+ else {
+ if ( aExp == 0x7FFF ) {
+ if ( aSig0 | aSig1 | bSig0 | bSig1 ) {
+ return propagateFloat128NaN( a, b );
+ }
+ return a;
+ }
+ add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
+ if ( aExp == 0 ) return packFloat128( zSign, 0, zSig0, zSig1 );
+ zSig2 = 0;
+ zSig0 |= LIT64( 0x0002000000000000 );
+ zExp = aExp;
+ goto shiftRight1;
+ }
+ aSig0 |= LIT64( 0x0001000000000000 );
+ add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
+ --zExp;
+ if ( zSig0 < LIT64( 0x0002000000000000 ) ) goto roundAndPack;
+ ++zExp;
+ shiftRight1:
+ shift128ExtraRightJamming(
+ zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 );
+ roundAndPack:
+ return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the absolute values of the quadruple-
+precision floating-point values `a' and `b'. If `zSign' is true, the
+difference is negated before being returned. `zSign' is ignored if the
+result is a NaN. The subtraction is performed according to the IEC/IEEE
+Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float128 subFloat128Sigs( float128 a, float128 b, flag zSign )
+{
+ int32 aExp, bExp, zExp;
+ bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1;
+ int32 expDiff;
+ float128 z;
+
+ aSig1 = extractFloat128Frac1( a );
+ aSig0 = extractFloat128Frac0( a );
+ aExp = extractFloat128Exp( a );
+ bSig1 = extractFloat128Frac1( b );
+ bSig0 = extractFloat128Frac0( b );
+ bExp = extractFloat128Exp( b );
+ expDiff = aExp - bExp;
+ shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 );
+ shortShift128Left( bSig0, bSig1, 14, &bSig0, &bSig1 );
+ if ( 0 < expDiff ) goto aExpBigger;
+ if ( expDiff < 0 ) goto bExpBigger;
+ if ( aExp == 0x7FFF ) {
+ if ( aSig0 | aSig1 | bSig0 | bSig1 ) {
+ return propagateFloat128NaN( a, b );
+ }
+ float_raise( float_flag_invalid );
+ z.low = float128_default_nan_low;
+ z.high = float128_default_nan_high;
+ return z;
+ }
+ if ( aExp == 0 ) {
+ aExp = 1;
+ bExp = 1;
+ }
+ if ( bSig0 < aSig0 ) goto aBigger;
+ if ( aSig0 < bSig0 ) goto bBigger;
+ if ( bSig1 < aSig1 ) goto aBigger;
+ if ( aSig1 < bSig1 ) goto bBigger;
+ return packFloat128( float_rounding_mode == float_round_down, 0, 0, 0 );
+ bExpBigger:
+ if ( bExp == 0x7FFF ) {
+ if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
+ return packFloat128( zSign ^ 1, 0x7FFF, 0, 0 );
+ }
+ if ( aExp == 0 ) {
+ ++expDiff;
+ }
+ else {
+ aSig0 |= LIT64( 0x4000000000000000 );
+ }
+ shift128RightJamming( aSig0, aSig1, - expDiff, &aSig0, &aSig1 );
+ bSig0 |= LIT64( 0x4000000000000000 );
+ bBigger:
+ sub128( bSig0, bSig1, aSig0, aSig1, &zSig0, &zSig1 );
+ zExp = bExp;
+ zSign ^= 1;
+ goto normalizeRoundAndPack;
+ aExpBigger:
+ if ( aExp == 0x7FFF ) {
+ if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) {
+ --expDiff;
+ }
+ else {
+ bSig0 |= LIT64( 0x4000000000000000 );
+ }
+ shift128RightJamming( bSig0, bSig1, expDiff, &bSig0, &bSig1 );
+ aSig0 |= LIT64( 0x4000000000000000 );
+ aBigger:
+ sub128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
+ zExp = aExp;
+ normalizeRoundAndPack:
+ --zExp;
+ return normalizeRoundAndPackFloat128( zSign, zExp - 14, zSig0, zSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the quadruple-precision floating-point values
+`a' and `b'. The operation is performed according to the IEC/IEEE Standard
+for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 float128_add( float128 a, float128 b )
+{
+ flag aSign, bSign;
+
+ aSign = extractFloat128Sign( a );
+ bSign = extractFloat128Sign( b );
+ if ( aSign == bSign ) {
+ return addFloat128Sigs( a, b, aSign );
+ }
+ else {
+ return subFloat128Sigs( a, b, aSign );
+ }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the quadruple-precision floating-point
+values `a' and `b'. The operation is performed according to the IEC/IEEE
+Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 float128_sub( float128 a, float128 b )
+{
+ flag aSign, bSign;
+
+ aSign = extractFloat128Sign( a );
+ bSign = extractFloat128Sign( b );
+ if ( aSign == bSign ) {
+ return subFloat128Sigs( a, b, aSign );
+ }
+ else {
+ return addFloat128Sigs( a, b, aSign );
+ }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of multiplying the quadruple-precision floating-point
+values `a' and `b'. The operation is performed according to the IEC/IEEE
+Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 float128_mul( float128 a, float128 b )
+{
+ flag aSign, bSign, zSign;
+ int32 aExp, bExp, zExp;
+ bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3;
+ float128 z;
+
+ aSig1 = extractFloat128Frac1( a );
+ aSig0 = extractFloat128Frac0( a );
+ aExp = extractFloat128Exp( a );
+ aSign = extractFloat128Sign( a );
+ bSig1 = extractFloat128Frac1( b );
+ bSig0 = extractFloat128Frac0( b );
+ bExp = extractFloat128Exp( b );
+ bSign = extractFloat128Sign( b );
+ zSign = aSign ^ bSign;
+ if ( aExp == 0x7FFF ) {
+ if ( ( aSig0 | aSig1 )
+ || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) {
+ return propagateFloat128NaN( a, b );
+ }
+ if ( ( bExp | bSig0 | bSig1 ) == 0 ) goto invalid;
+ return packFloat128( zSign, 0x7FFF, 0, 0 );
+ }
+ if ( bExp == 0x7FFF ) {
+ if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
+ if ( ( aExp | aSig0 | aSig1 ) == 0 ) {
+ invalid:
+ float_raise( float_flag_invalid );
+ z.low = float128_default_nan_low;
+ z.high = float128_default_nan_high;
+ return z;
+ }
+ return packFloat128( zSign, 0x7FFF, 0, 0 );
+ }
+ if ( aExp == 0 ) {
+ if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 );
+ normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
+ }
+ if ( bExp == 0 ) {
+ if ( ( bSig0 | bSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 );
+ normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
+ }
+ zExp = aExp + bExp - 0x4000;
+ aSig0 |= LIT64( 0x0001000000000000 );
+ shortShift128Left( bSig0, bSig1, 16, &bSig0, &bSig1 );
+ mul128To256( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1, &zSig2, &zSig3 );
+ add128( zSig0, zSig1, aSig0, aSig1, &zSig0, &zSig1 );
+ zSig2 |= ( zSig3 != 0 );
+ if ( LIT64( 0x0002000000000000 ) <= zSig0 ) {
+ shift128ExtraRightJamming(
+ zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 );
+ ++zExp;
+ }
+ return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of dividing the quadruple-precision floating-point value
+`a' by the corresponding value `b'. The operation is performed according to
+the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 float128_div( float128 a, float128 b )
+{
+ flag aSign, bSign, zSign;
+ int32 aExp, bExp, zExp;
+ bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
+ bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
+ float128 z;
+
+ aSig1 = extractFloat128Frac1( a );
+ aSig0 = extractFloat128Frac0( a );
+ aExp = extractFloat128Exp( a );
+ aSign = extractFloat128Sign( a );
+ bSig1 = extractFloat128Frac1( b );
+ bSig0 = extractFloat128Frac0( b );
+ bExp = extractFloat128Exp( b );
+ bSign = extractFloat128Sign( b );
+ zSign = aSign ^ bSign;
+ if ( aExp == 0x7FFF ) {
+ if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b );
+ if ( bExp == 0x7FFF ) {
+ if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
+ goto invalid;
+ }
+ return packFloat128( zSign, 0x7FFF, 0, 0 );
+ }
+ if ( bExp == 0x7FFF ) {
+ if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
+ return packFloat128( zSign, 0, 0, 0 );
+ }
+ if ( bExp == 0 ) {
+ if ( ( bSig0 | bSig1 ) == 0 ) {
+ if ( ( aExp | aSig0 | aSig1 ) == 0 ) {
+ invalid:
+ float_raise( float_flag_invalid );
+ z.low = float128_default_nan_low;
+ z.high = float128_default_nan_high;
+ return z;
+ }
+ float_raise( float_flag_divbyzero );
+ return packFloat128( zSign, 0x7FFF, 0, 0 );
+ }
+ normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
+ }
+ if ( aExp == 0 ) {
+ if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 );
+ normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
+ }
+ zExp = aExp - bExp + 0x3FFD;
+ shortShift128Left(
+ aSig0 | LIT64( 0x0001000000000000 ), aSig1, 15, &aSig0, &aSig1 );
+ shortShift128Left(
+ bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 );
+ if ( le128( bSig0, bSig1, aSig0, aSig1 ) ) {
+ shift128Right( aSig0, aSig1, 1, &aSig0, &aSig1 );
+ ++zExp;
+ }
+ zSig0 = estimateDiv128To64( aSig0, aSig1, bSig0 );
+ mul128By64To192( bSig0, bSig1, zSig0, &term0, &term1, &term2 );
+ sub192( aSig0, aSig1, 0, term0, term1, term2, &rem0, &rem1, &rem2 );
+ while ( (sbits64) rem0 < 0 ) {
+ --zSig0;
+ add192( rem0, rem1, rem2, 0, bSig0, bSig1, &rem0, &rem1, &rem2 );
+ }
+ zSig1 = estimateDiv128To64( rem1, rem2, bSig0 );
+ if ( ( zSig1 & 0x3FFF ) <= 4 ) {
+ mul128By64To192( bSig0, bSig1, zSig1, &term1, &term2, &term3 );
+ sub192( rem1, rem2, 0, term1, term2, term3, &rem1, &rem2, &rem3 );
+ while ( (sbits64) rem1 < 0 ) {
+ --zSig1;
+ add192( rem1, rem2, rem3, 0, bSig0, bSig1, &rem1, &rem2, &rem3 );
+ }
+ zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
+ }
+ shift128ExtraRightJamming( zSig0, zSig1, 0, 15, &zSig0, &zSig1, &zSig2 );
+ return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the remainder of the quadruple-precision floating-point value `a'
+with respect to the corresponding value `b'. The operation is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 float128_rem( float128 a, float128 b )
+{
+ flag aSign, bSign, zSign;
+ int32 aExp, bExp, expDiff;
+ bits64 aSig0, aSig1, bSig0, bSig1;
+ bits64 q, term0, term1, term2, allZero, alternateASig0, alternateASig1;
+ bits64 sigMean1;
+ sbits64 sigMean0;
+ float128 z;
+
+ aSig1 = extractFloat128Frac1( a );
+ aSig0 = extractFloat128Frac0( a );
+ aExp = extractFloat128Exp( a );
+ aSign = extractFloat128Sign( a );
+ bSig1 = extractFloat128Frac1( b );
+ bSig0 = extractFloat128Frac0( b );
+ bExp = extractFloat128Exp( b );
+ bSign = extractFloat128Sign( b );
+ if ( aExp == 0x7FFF ) {
+ if ( ( aSig0 | aSig1 )
+ || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) {
+ return propagateFloat128NaN( a, b );
+ }
+ goto invalid;
+ }
+ if ( bExp == 0x7FFF ) {
+ if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) {
+ if ( ( bSig0 | bSig1 ) == 0 ) {
+ invalid:
+ float_raise( float_flag_invalid );
+ z.low = float128_default_nan_low;
+ z.high = float128_default_nan_high;
+ return z;
+ }
+ normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
+ }
+ if ( aExp == 0 ) {
+ if ( ( aSig0 | aSig1 ) == 0 ) return a;
+ normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
+ }
+ expDiff = aExp - bExp;
+ if ( expDiff < -1 ) return a;
+ shortShift128Left(
+ aSig0 | LIT64( 0x0001000000000000 ),
+ aSig1,
+ 15 - ( expDiff < 0 ),
+ &aSig0,
+ &aSig1
+ );
+ shortShift128Left(
+ bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 );
+ q = le128( bSig0, bSig1, aSig0, aSig1 );
+ if ( q ) sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 );
+ expDiff -= 64;
+ while ( 0 < expDiff ) {
+ q = estimateDiv128To64( aSig0, aSig1, bSig0 );
+ q = ( 4 < q ) ? q - 4 : 0;
+ mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 );
+ shortShift192Left( term0, term1, term2, 61, &term1, &term2, &allZero );
+ shortShift128Left( aSig0, aSig1, 61, &aSig0, &allZero );
+ sub128( aSig0, 0, term1, term2, &aSig0, &aSig1 );
+ expDiff -= 61;
+ }
+ if ( -64 < expDiff ) {
+ q = estimateDiv128To64( aSig0, aSig1, bSig0 );
+ q = ( 4 < q ) ? q - 4 : 0;
+ q >>= - expDiff;
+ shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 );
+ expDiff += 52;
+ if ( expDiff < 0 ) {
+ shift128Right( aSig0, aSig1, - expDiff, &aSig0, &aSig1 );
+ }
+ else {
+ shortShift128Left( aSig0, aSig1, expDiff, &aSig0, &aSig1 );
+ }
+ mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 );
+ sub128( aSig0, aSig1, term1, term2, &aSig0, &aSig1 );
+ }
+ else {
+ shift128Right( aSig0, aSig1, 12, &aSig0, &aSig1 );
+ shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 );
+ }
+ do {
+ alternateASig0 = aSig0;
+ alternateASig1 = aSig1;
+ ++q;
+ sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 );
+ } while ( 0 <= (sbits64) aSig0 );
+ add128(
+ aSig0, aSig1, alternateASig0, alternateASig1, &sigMean0, &sigMean1 );
+ if ( ( sigMean0 < 0 )
+ || ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) {
+ aSig0 = alternateASig0;
+ aSig1 = alternateASig1;
+ }
+ zSign = ( (sbits64) aSig0 < 0 );
+ if ( zSign ) sub128( 0, 0, aSig0, aSig1, &aSig0, &aSig1 );
+ return
+ normalizeRoundAndPackFloat128( aSign ^ zSign, bExp - 4, aSig0, aSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the square root of the quadruple-precision floating-point value `a'.
+The operation is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 float128_sqrt( float128 a )
+{
+ flag aSign;
+ int32 aExp, zExp;
+ bits64 aSig0, aSig1, zSig0, zSig1, zSig2;
+ bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
+ bits64 shiftedRem0, shiftedRem1;
+ float128 z;
+
+ aSig1 = extractFloat128Frac1( a );
+ aSig0 = extractFloat128Frac0( a );
+ aExp = extractFloat128Exp( a );
+ aSign = extractFloat128Sign( a );
+ if ( aExp == 0x7FFF ) {
+ if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, a );
+ if ( ! aSign ) return a;
+ goto invalid;
+ }
+ if ( aSign ) {
+ if ( ( aExp | aSig0 | aSig1 ) == 0 ) return a;
+ invalid:
+ float_raise( float_flag_invalid );
+ z.low = float128_default_nan_low;
+ z.high = float128_default_nan_high;
+ return z;
+ }
+ if ( aExp == 0 ) {
+ if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( 0, 0, 0, 0 );
+ normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
+ }
+ zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFE;
+ aSig0 |= LIT64( 0x0001000000000000 );
+ zSig0 = estimateSqrt32( aExp, aSig0>>17 );
+ zSig0 <<= 31;
+ shortShift128Left( aSig0, aSig1, 13 - ( aExp & 1 ), &aSig0, &aSig1 );
+ zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0 ) + zSig0 + 4;
+ if ( 0 <= (sbits64) zSig0 ) zSig0 = LIT64( 0xFFFFFFFFFFFFFFFF );
+ shortShift128Left( aSig0, aSig1, 2, &aSig0, &aSig1 );
+ mul64To128( zSig0, zSig0, &term0, &term1 );
+ sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 );
+ while ( (sbits64) rem0 < 0 ) {
+ --zSig0;
+ shortShift128Left( 0, zSig0, 1, &term0, &term1 );
+ term1 |= 1;
+ add128( rem0, rem1, term0, term1, &rem0, &rem1 );
+ }
+ shortShift128Left( rem0, rem1, 63, &shiftedRem0, &shiftedRem1 );
+ zSig1 = estimateDiv128To64( shiftedRem0, shiftedRem1, zSig0 );
+ if ( ( zSig1 & 0x3FFF ) <= 5 ) {
+ if ( zSig1 == 0 ) zSig1 = 1;
+ mul64To128( zSig0, zSig1, &term1, &term2 );
+ shortShift128Left( term1, term2, 1, &term1, &term2 );
+ sub128( rem1, 0, term1, term2, &rem1, &rem2 );
+ mul64To128( zSig1, zSig1, &term2, &term3 );
+ sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 );
+ while ( (sbits64) rem1 < 0 ) {
+ --zSig1;
+ shortShift192Left( 0, zSig0, zSig1, 1, &term1, &term2, &term3 );
+ term3 |= 1;
+ add192(
+ rem1, rem2, rem3, term1, term2, term3, &rem1, &rem2, &rem3 );
+ }
+ zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
+ }
+ shift128ExtraRightJamming( zSig0, zSig1, 0, 15, &zSig0, &zSig1, &zSig2 );
+ return roundAndPackFloat128( 0, zExp, zSig0, zSig1, zSig2 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the quadruple-precision floating-point value `a' is equal to
+the corresponding value `b', and 0 otherwise. The comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float128_eq( float128 a, float128 b )
+{
+
+ if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
+ && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+ || ( ( extractFloat128Exp( b ) == 0x7FFF )
+ && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+ ) {
+ if ( float128_is_signaling_nan( a )
+ || float128_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ return
+ ( a.low == b.low )
+ && ( ( a.high == b.high )
+ || ( ( a.low == 0 )
+ && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) )
+ );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the quadruple-precision floating-point value `a' is less than
+or equal to the corresponding value `b', and 0 otherwise. The comparison
+is performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float128_le( float128 a, float128 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
+ && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+ || ( ( extractFloat128Exp( b ) == 0x7FFF )
+ && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ aSign = extractFloat128Sign( a );
+ bSign = extractFloat128Sign( b );
+ if ( aSign != bSign ) {
+ return
+ aSign
+ || ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+ == 0 );
+ }
+ return
+ aSign ? le128( b.high, b.low, a.high, a.low )
+ : le128( a.high, a.low, b.high, b.low );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the quadruple-precision floating-point value `a' is less than
+the corresponding value `b', and 0 otherwise. The comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float128_lt( float128 a, float128 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
+ && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+ || ( ( extractFloat128Exp( b ) == 0x7FFF )
+ && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ aSign = extractFloat128Sign( a );
+ bSign = extractFloat128Sign( b );
+ if ( aSign != bSign ) {
+ return
+ aSign
+ && ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+ != 0 );
+ }
+ return
+ aSign ? lt128( b.high, b.low, a.high, a.low )
+ : lt128( a.high, a.low, b.high, b.low );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the quadruple-precision floating-point value `a' is equal to
+the corresponding value `b', and 0 otherwise. The invalid exception is
+raised if either operand is a NaN. Otherwise, the comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float128_eq_signaling( float128 a, float128 b )
+{
+
+ if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
+ && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+ || ( ( extractFloat128Exp( b ) == 0x7FFF )
+ && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ return
+ ( a.low == b.low )
+ && ( ( a.high == b.high )
+ || ( ( a.low == 0 )
+ && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) )
+ );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the quadruple-precision floating-point value `a' is less than
+or equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not
+cause an exception. Otherwise, the comparison is performed according to the
+IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float128_le_quiet( float128 a, float128 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
+ && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+ || ( ( extractFloat128Exp( b ) == 0x7FFF )
+ && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+ ) {
+ if ( float128_is_signaling_nan( a )
+ || float128_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ aSign = extractFloat128Sign( a );
+ bSign = extractFloat128Sign( b );
+ if ( aSign != bSign ) {
+ return
+ aSign
+ || ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+ == 0 );
+ }
+ return
+ aSign ? le128( b.high, b.low, a.high, a.low )
+ : le128( a.high, a.low, b.high, b.low );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the quadruple-precision floating-point value `a' is less than
+the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an
+exception. Otherwise, the comparison is performed according to the IEC/IEEE
+Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float128_lt_quiet( float128 a, float128 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
+ && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+ || ( ( extractFloat128Exp( b ) == 0x7FFF )
+ && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+ ) {
+ if ( float128_is_signaling_nan( a )
+ || float128_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ aSign = extractFloat128Sign( a );
+ bSign = extractFloat128Sign( b );
+ if ( aSign != bSign ) {
+ return
+ aSign
+ && ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+ != 0 );
+ }
+ return
+ aSign ? lt128( b.high, b.low, a.high, a.low )
+ : lt128( a.high, a.low, b.high, b.low );
+
+}
+
+#endif
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/nwfpe/softfloat.h linux.ac/arch/arm/nwfpe/softfloat.h
--- linux.vanilla/arch/arm/nwfpe/softfloat.h Thu Jan 1 01:00:00 1970
+++ linux.ac/arch/arm/nwfpe/softfloat.h Tue Feb 2 20:59:51 1999
@@ -0,0 +1,290 @@
+
+/*
+===============================================================================
+
+This C header file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/softfloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these three paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+#ifndef __SOFTFLOAT_H__
+#define __SOFTFLOAT_H__
+
+/*
+-------------------------------------------------------------------------------
+The macro `FLOATX80' must be defined to enable the extended double-precision
+floating-point format `floatx80'. If this macro is not defined, the
+`floatx80' type will not be defined, and none of the functions that either
+input or output the `floatx80' type will be defined. The same applies to
+the `FLOAT128' macro and the quadruple-precision format `float128'.
+-------------------------------------------------------------------------------
+*/
+#define FLOATX80
+/* #define FLOAT128 */
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point types.
+-------------------------------------------------------------------------------
+*/
+typedef unsigned long int float32;
+typedef unsigned long long float64;
+#ifdef FLOATX80
+typedef struct {
+ unsigned short high;
+ unsigned long long low;
+} floatx80;
+#endif
+#ifdef FLOAT128
+typedef struct {
+ unsigned long long high, low;
+} float128;
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point underflow tininess-detection mode.
+-------------------------------------------------------------------------------
+*/
+extern signed char float_detect_tininess;
+enum {
+ float_tininess_after_rounding = 0,
+ float_tininess_before_rounding = 1
+};
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point rounding mode.
+-------------------------------------------------------------------------------
+*/
+extern signed char float_rounding_mode;
+enum {
+ float_round_nearest_even = 0,
+ float_round_to_zero = 1,
+ float_round_down = 2,
+ float_round_up = 3
+};
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point exception flags.
+-------------------------------------------------------------------------------
+extern signed char float_exception_flags;
+enum {
+ float_flag_inexact = 1,
+ float_flag_underflow = 2,
+ float_flag_overflow = 4,
+ float_flag_divbyzero = 8,
+ float_flag_invalid = 16
+};
+
+ScottB: November 4, 1998
+Changed the enumeration to match the bit order in the FPA11.
+*/
+
+extern signed char float_exception_flags;
+enum {
+ float_flag_invalid = 1,
+ float_flag_divbyzero = 2,
+ float_flag_overflow = 4,
+ float_flag_underflow = 8,
+ float_flag_inexact = 16
+};
+
+/*
+-------------------------------------------------------------------------------
+Routine to raise any or all of the software IEC/IEEE floating-point
+exception flags.
+-------------------------------------------------------------------------------
+*/
+void float_raise( signed char );
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE integer-to-floating-point conversion routines.
+-------------------------------------------------------------------------------
+*/
+float32 int32_to_float32( signed int );
+float64 int32_to_float64( signed int );
+#ifdef FLOATX80
+floatx80 int32_to_floatx80( signed int );
+#endif
+#ifdef FLOAT128
+float128 int32_to_float128( signed int );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE single-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+signed int float32_to_int32( float32 );
+signed int float32_to_int32_round_to_zero( float32 );
+float64 float32_to_float64( float32 );
+#ifdef FLOATX80
+floatx80 float32_to_floatx80( float32 );
+#endif
+#ifdef FLOAT128
+float128 float32_to_float128( float32 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE single-precision operations.
+-------------------------------------------------------------------------------
+*/
+float32 float32_round_to_int( float32 );
+float32 float32_add( float32, float32 );
+float32 float32_sub( float32, float32 );
+float32 float32_mul( float32, float32 );
+float32 float32_div( float32, float32 );
+float32 float32_rem( float32, float32 );
+float32 float32_sqrt( float32 );
+char float32_eq( float32, float32 );
+char float32_le( float32, float32 );
+char float32_lt( float32, float32 );
+char float32_eq_signaling( float32, float32 );
+char float32_le_quiet( float32, float32 );
+char float32_lt_quiet( float32, float32 );
+char float32_is_signaling_nan( float32 );
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE double-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+signed int float64_to_int32( float64 );
+signed int float64_to_int32_round_to_zero( float64 );
+float32 float64_to_float32( float64 );
+#ifdef FLOATX80
+floatx80 float64_to_floatx80( float64 );
+#endif
+#ifdef FLOAT128
+float128 float64_to_float128( float64 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE double-precision operations.
+-------------------------------------------------------------------------------
+*/
+float64 float64_round_to_int( float64 );
+float64 float64_add( float64, float64 );
+float64 float64_sub( float64, float64 );
+float64 float64_mul( float64, float64 );
+float64 float64_div( float64, float64 );
+float64 float64_rem( float64, float64 );
+float64 float64_sqrt( float64 );
+char float64_eq( float64, float64 );
+char float64_le( float64, float64 );
+char float64_lt( float64, float64 );
+char float64_eq_signaling( float64, float64 );
+char float64_le_quiet( float64, float64 );
+char float64_lt_quiet( float64, float64 );
+char float64_is_signaling_nan( float64 );
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+signed int floatx80_to_int32( floatx80 );
+signed int floatx80_to_int32_round_to_zero( floatx80 );
+float32 floatx80_to_float32( floatx80 );
+float64 floatx80_to_float64( floatx80 );
+#ifdef FLOAT128
+float128 floatx80_to_float128( floatx80 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision rounding precision. Valid
+values are 32, 64, and 80.
+-------------------------------------------------------------------------------
+*/
+extern signed char floatx80_rounding_precision;
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision operations.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_round_to_int( floatx80 );
+floatx80 floatx80_add( floatx80, floatx80 );
+floatx80 floatx80_sub( floatx80, floatx80 );
+floatx80 floatx80_mul( floatx80, floatx80 );
+floatx80 floatx80_div( floatx80, floatx80 );
+floatx80 floatx80_rem( floatx80, floatx80 );
+floatx80 floatx80_sqrt( floatx80 );
+char floatx80_eq( floatx80, floatx80 );
+char floatx80_le( floatx80, floatx80 );
+char floatx80_lt( floatx80, floatx80 );
+char floatx80_eq_signaling( floatx80, floatx80 );
+char floatx80_le_quiet( floatx80, floatx80 );
+char floatx80_lt_quiet( floatx80, floatx80 );
+char floatx80_is_signaling_nan( floatx80 );
+
+#endif
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE quadruple-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+signed int float128_to_int32( float128 );
+signed int float128_to_int32_round_to_zero( float128 );
+float32 float128_to_float32( float128 );
+float64 float128_to_float64( float128 );
+#ifdef FLOATX80
+floatx80 float128_to_floatx80( float128 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE quadruple-precision operations.
+-------------------------------------------------------------------------------
+*/
+float128 float128_round_to_int( float128 );
+float128 float128_add( float128, float128 );
+float128 float128_sub( float128, float128 );
+float128 float128_mul( float128, float128 );
+float128 float128_div( float128, float128 );
+float128 float128_rem( float128, float128 );
+float128 float128_sqrt( float128 );
+char float128_eq( float128, float128 );
+char float128_le( float128, float128 );
+char float128_lt( float128, float128 );
+char float128_eq_signaling( float128, float128 );
+char float128_le_quiet( float128, float128 );
+char float128_lt_quiet( float128, float128 );
+char float128_is_signaling_nan( float128 );
+
+#endif
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/vmlinux-armv.lds linux.ac/arch/arm/vmlinux-armv.lds
--- linux.vanilla/arch/arm/vmlinux-armv.lds Sun Nov 8 15:08:45 1998
+++ linux.ac/arch/arm/vmlinux-armv.lds Fri Jan 22 14:10:49 1999
@@ -7,50 +7,64 @@
ENTRY(_start)
SECTIONS
{
- _text = .; /* Text and read-only data */
- .text : {
+ _text = .; /* Text and read-only data */
+ .text : { } /* Set text start address */
+
+ __init_begin = .; /* Init code and data */
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(4096);
+ __init_end = .;
+
+ __ebsa285_begin = .;
+ .text.ebsa285 : { *(.text.ebsa285) }
+ .data.ebsa285 : { *(.data.ebsa285) }
+ . = ALIGN(4096);
+ __ebsa285_end = .;
+
+ __netwinder_begin = .;
+ .text.netwinder : { *(.text.netwinder) }
+ .data.netwinder : { *(.data.netwinder) }
+ . = ALIGN(4096);
+ __netwinder_end = .;
+
+ .text.real : { /* Real text segment */
*(.text)
*(.fixup)
*(.gnu.warning)
- } = 0x9090
+ }
+
.text.lock : { *(.text.lock) } /* out-of-line lock text */
.rodata : { *(.rodata) }
.kstrtab : { *(.kstrtab) }
- . = ALIGN(16); /* Exception table */
+ . = ALIGN(16); /* Exception table */
__start___ex_table = .;
__ex_table : { *(__ex_table) }
__stop___ex_table = .;
- __start___ksymtab = .; /* Kernel symbol table */
+ __start___ksymtab = .; /* Kernel symbol table */
__ksymtab : { *(__ksymtab) }
__stop___ksymtab = .;
- _etext = .; /* End of text section */
+ _etext = .; /* End of text section */
. = ALIGN(8192);
- .data : { /* Data */
+ .data : { /* Data */
*(.init.task)
*(.data)
CONSTRUCTORS
}
- _edata = .; /* End of data section */
-
- . = ALIGN(4096); /* Init code and data */
- __init_begin = .;
- .text.init : { *(.text.init) }
- .data.init : { *(.data.init) }
- . = ALIGN(4096);
- __init_end = .;
+ _edata = .; /* End of data section */
- __bss_start = .; /* BSS */
+ __bss_start = .; /* BSS */
.bss : {
*(.bss)
}
_end = . ;
- /* Stabs debugging sections. */
+ /* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/defconfig linux.ac/arch/i386/defconfig
--- linux.vanilla/arch/i386/defconfig Tue Feb 23 14:21:32 1999
+++ linux.ac/arch/i386/defconfig Fri Feb 26 01:59:54 1999
@@ -104,7 +104,6 @@
CONFIG_PACKET=y
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
-# CONFIG_NET_ALIAS is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
@@ -121,7 +120,6 @@
# (it is safe to leave these untouched)
#
# CONFIG_INET_RARP is not set
-CONFIG_IP_NOSR=y
CONFIG_SKB_LARGE=y
#
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/init_task.c linux.ac/arch/i386/kernel/init_task.c
--- linux.vanilla/arch/i386/kernel/init_task.c Sun Nov 8 15:08:22 1998
+++ linux.ac/arch/i386/kernel/init_task.c Fri Dec 4 17:14:23 1998
@@ -7,7 +7,6 @@
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
-static struct file * init_fd_array[NR_OPEN] = { NULL, };
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
struct mm_struct init_mm = INIT_MM;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/mtrr.c linux.ac/arch/i386/kernel/mtrr.c
--- linux.vanilla/arch/i386/kernel/mtrr.c Mon Dec 28 23:09:40 1998
+++ linux.ac/arch/i386/kernel/mtrr.c Tue Mar 2 01:15:36 1999
@@ -132,6 +132,11 @@
Fixed harmless compiler warning in include/asm-i386/mtrr.h
Fixed version numbering and history for v1.23 -> v1.24.
v1.26
+
+ v1.26ac Alan Cox
+ Added some K6-II/III support. This needs back merging with
+ Richard's current code before it goes to Linus really.
+
*/
#include
#include
@@ -197,7 +202,7 @@
# define MTRR_CHANGE_MASK_DEFTYPE 0x04
#endif
-/* In the processor's MTRR interface, the MTRR type is always held in
+/* In the intel processor's MTRR interface, the MTRR type is always held in
an 8 bit field: */
typedef u8 mtrr_type;
@@ -225,6 +230,7 @@
#ifdef CONFIG_PROC_FS
static void compute_ascii (void);
#endif
+static int k6_has_ranges(void);
struct set_mtrr_context
@@ -236,6 +242,15 @@
};
/*
+ * No point continually digging through complex CPU conditionals..
+ */
+
+static int mtrr_flags;
+
+#define MTRR_PRESENT 1
+#define MTRR_WRCOMB 2
+
+/*
* Access to machine-specific registers (available on 586 and better only)
* Note: the rd* operations modify the parameters directly (without using
* pointer indirection), this allows gcc to optimize better
@@ -267,13 +282,15 @@
/* disable interrupts locally */
__save_flags (ctxt->flags); __cli ();
+ if(boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
+ return;
+
/* save value of CR4 and clear Page Global Enable (bit 7) */
asm volatile ("movl %%cr4, %0\n\t"
"movl %0, %1\n\t"
"andb $0x7f, %b1\n\t"
"movl %1, %%cr4\n\t"
: "=r" (ctxt->cr4val), "=q" (tmp) : : "memory");
-
/* disable and flush caches. Note that wbinvd flushes the TLBs as
a side-effect. */
asm volatile ("movl %%cr0, %0\n\t"
@@ -294,6 +311,9 @@
{
unsigned long tmp;
+ if(boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
+ return;
+
/* flush caches and TLBs */
asm volatile ("wbinvd" : : : "memory" );
@@ -319,6 +339,9 @@
static unsigned int get_num_var_ranges (void)
{
unsigned long config, dummy;
+
+ if(boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
+ return 2;
rdmsr(MTRRcap_MSR, config, dummy);
return (config & 0xff);
@@ -340,6 +363,46 @@
{
unsigned long dummy, mask_lo, base_lo;
+ if(boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
+ {
+ unsigned long low, high;
+ rdmsr(0xC0000085, low, high);
+ /* Upper dword is region 1, lower is region 0 */
+ if(reg==1)
+ low=high;
+ /* The base masks off on the right alignment */
+ *base=low&0xFFFE0000;
+ *type=0;
+ if(low&1)
+ *type=MTRR_TYPE_UNCACHABLE;
+ if(low&2)
+ *type=MTRR_TYPE_WRCOMB;
+ if(!(low&3))
+ {
+ *size=0;
+ return;
+ }
+
+ /*
+ * This needs a little explaining. The size is stored as an
+ * inverted mask of bits of 128K granularity 15 bits long offset
+ * 2 bits
+ *
+ * So to get a size we do invert the mask and add 1 to the lowest
+ * mask bit (4 as its 2 bits in). This gives us a size we then shift
+ * to turn into 128K blocks
+ *
+ * eg 111 1111 1111 1100 is 512K
+ *
+ * invert 000 0000 0000 0011
+ * +1 000 0000 0000 0100
+ * *128K ...
+ */
+
+ low=(~low)&0x1FFFC;
+ *size = (low+4)<<15;
+ return;
+ }
rdmsr(MTRRphysMask_MSR(reg), mask_lo, dummy);
if ((mask_lo & 0x800) == 0) {
/* Invalid (i.e. free) range. */
@@ -381,16 +444,56 @@
struct set_mtrr_context ctxt;
if (do_safe) set_mtrr_prepare (&ctxt);
- if (size == 0)
+
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
{
- /* The invalid bit is kept in the mask, so we simply clear the
- relevant mask register to disable a range. */
- wrmsr (MTRRphysMask_MSR (reg), 0, 0);
+ if (size == 0)
+ {
+ /* The invalid bit is kept in the mask, so we simply clear the
+ relevant mask register to disable a range. */
+ wrmsr (MTRRphysMask_MSR (reg), 0, 0);
+ }
+ else
+ {
+ wrmsr (MTRRphysBase_MSR (reg), base | type, 0);
+ wrmsr (MTRRphysMask_MSR (reg), ~(size - 1) | 0x800, 0);
+ }
}
- else
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
{
- wrmsr (MTRRphysBase_MSR (reg), base | type, 0);
- wrmsr (MTRRphysMask_MSR (reg), ~(size - 1) | 0x800, 0);
+ u32 low, high;
+ unsigned long flags;
+ /*
+ * Low is MTRR0 , High MTRR 1
+ */
+ rdmsr(0xC0000085, low, high);
+ /*
+ * Blank to disable
+ */
+ if(size==0)
+ *(reg?&high:&low)=0;
+ else
+ /* Set the register to the base (already shifted for us), the
+ type (off by one) and an inverted bitmask of the size
+
+ The size is the only odd bit. We are fed say 512K
+ We invert this and we get 111 1111 1111 1011 but
+ if you subtract one and invert you get the desired
+ 111 1111 1111 1100 mask
+ */
+
+ *(reg?&high:&low)=(((~(size-1))>>15)&0x0001FFFC)|base|(type+1);
+
+ /*
+ * The writeback rule is quite specific. See the manual. Its
+ * disable local interrupts, write back the cache, set the mtrr
+ */
+
+ save_flags(flags);
+ __cli();
+ __asm__ __volatile__("wbinvd" : : : "memory");
+ wrmsr(0xC0000085, low, high);
+ restore_flags(flags);
}
if (do_safe) set_mtrr_done (&ctxt);
} /* End Function set_mtrr_up */
@@ -518,11 +621,16 @@
for (i = 0; i < nvrs; i++)
get_mtrr_var_range(i, &vrs[i]);
- get_fixed_ranges(state->fixed_ranges);
+ if(boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
+ {
+ get_fixed_ranges(state->fixed_ranges);
- rdmsr(MTRRdefType_MSR, lo, dummy);
- state->def_type = (lo & 0xff);
- state->enabled = (lo & 0xc00) >> 10;
+ rdmsr(MTRRdefType_MSR, lo, dummy);
+ state->def_type = (lo & 0xff);
+ state->enabled = (lo & 0xc00) >> 10;
+ }
+ state->def_type = 0;
+ state->enabled = 1;
} /* End Function get_mtrr_state */
@@ -545,6 +653,9 @@
unsigned int i;
unsigned long change_mask = 0;
+ if(boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
+ return 0UL;
+
for (i = 0; i < state->num_var_ranges; i++)
if (set_mtrr_var_range_testing(i, &state->var_ranges[i]))
change_mask |= MTRR_CHANGE_MASK_VARIABLE;
@@ -737,40 +848,58 @@
mtrr_type ltype;
unsigned long lbase, lsize, last;
- if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV;
- if ( (base & 0xfff) || (size & 0xfff) )
- {
- printk ("mtrr: size and base must be multiples of 4kB\n");
- printk ("mtrr: size: %lx base: %lx\n", size, base);
- return -EINVAL;
- }
- if (base + size < 0x100000)
- {
- printk ("mtrr: cannot set region below 1 MByte (0x%lx,0x%lx)\n",
- base, size);
- return -EINVAL;
+ if (!(mtrr_flags&MTRR_PRESENT))
+ return -ENODEV;
+
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
+ {
+ /* Apply the K6 block alignment and size rules
+ In order
+ o Uncached or gathering only
+ o 128K or bigger block
+ o Power of 2 block
+ o base suitably aligned to the power
+ */
+ if(type > 1 || size < (1<<17) || (size & ~(size-1))-size || (base&(size-1)))
+ return -EINVAL;
}
- /* Check upper bits of base and last are equal and lower bits are 0 for
- base and 1 for last */
- last = base + size - 1;
- for (lbase = base; !(lbase & 1) && (last & 1);
- lbase = lbase >> 1, last = last >> 1);
- if (lbase != last)
+
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
{
- printk ("mtrr: base(0x%lx) is not aligned on a size(0x%lx) boundary\n",
- base, size);
- return -EINVAL;
- }
- if (type >= MTRR_NUM_TYPES)
- {
- printk ("mtrr: type: %u illegal\n", type);
- return -EINVAL;
- }
- /* If the type is WC, check that this processor supports it */
- if ( (type == MTRR_TYPE_WRCOMB) && !have_wrcomb () )
- {
- printk ("mtrr: your processor doesn't support write-combining\n");
- return -ENOSYS;
+ if ( (base & 0xfff) || (size & 0xfff) )
+ {
+ printk ("mtrr: size and base must be multiples of 4kB\n");
+ printk ("mtrr: size: %lx base: %lx\n", size, base);
+ return -EINVAL;
+ }
+ if (base + size < 0x100000)
+ {
+ printk ("mtrr: cannot set region below 1 MByte (0x%lx,0x%lx)\n",
+ base, size);
+ return -EINVAL;
+ }
+ /* Check upper bits of base and last are equal and lower bits are 0 for
+ base and 1 for last */
+ last = base + size - 1;
+ for (lbase = base; !(lbase & 1) && (last & 1);
+ lbase = lbase >> 1, last = last >> 1);
+ if (lbase != last)
+ {
+ printk ("mtrr: base(0x%lx) is not aligned on a size(0x%lx) boundary\n",
+ base, size);
+ return -EINVAL;
+ }
+ if (type >= MTRR_NUM_TYPES)
+ {
+ printk ("mtrr: type: %u illegal\n", type);
+ return -EINVAL;
+ }
+ /* If the type is WC, check that this processor supports it */
+ if ( (type == MTRR_TYPE_WRCOMB) && !have_wrcomb () )
+ {
+ printk ("mtrr: your processor doesn't support write-combining\n");
+ return -EINVAL;
+ }
}
increment = increment ? 1 : 0;
max = get_num_var_ranges ();
@@ -834,7 +963,7 @@
mtrr_type ltype;
unsigned long lbase, lsize;
- if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV;
+ if ( !(mtrr_flags&MTRR_PRESENT) ) return -ENODEV;
max = get_num_var_ranges ();
spin_lock (&main_lock);
if (reg < 0)
@@ -1153,10 +1282,15 @@
__initfunc(void mtrr_init_boot_cpu (void))
{
- if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return;
printk("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION);
-
- get_mtrr_state (&smp_mtrr_state);
+ if (boot_cpu_data.x86_capability & X86_FEATURE_MTRR)
+ {
+ get_mtrr_state (&smp_mtrr_state);
+ }
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && k6_has_ranges())
+ {
+ get_mtrr_state (&smp_mtrr_state);
+ }
} /* End Function mtrr_init_boot_cpu */
__initfunc(void mtrr_init_secondary_cpu (void))
@@ -1181,9 +1315,35 @@
#endif /* __SMP__ */
+/*
+ * The extended memory handling is available on the K6-III and the
+ * K6-II stepping 8 and higher only.
+ */
+
+static int k6_has_ranges(void)
+{
+ if(boot_cpu_data.x86 !=5)
+ return 0;
+ if(boot_cpu_data.x86_model == 9 ||
+ (boot_cpu_data.x86_model == 8 &&
+ boot_cpu_data.x86_mask >= 8))
+ return 1;
+ return 0;
+}
+
__initfunc(int mtrr_init(void))
{
- if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return 0;
+ if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD && k6_has_ranges())
+ {
+# ifdef CONFIG_PROC_FS
+ proc_register (&proc_root, &proc_root_mtrr);
+# endif
+ mtrr_flags|=MTRR_PRESENT|MTRR_WRCOMB;
+ init_table();
+ return 0;
+ }
+ if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) )
+ return 0;
# ifndef __SMP__
printk("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION);
# endif
@@ -1197,6 +1357,7 @@
proc_register (&proc_root, &proc_root_mtrr);
# endif
+ mtrr_flags|=MTRR_PRESENT;
init_table ();
return 0;
} /* End Function mtrr_init */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/process.c linux.ac/arch/i386/kernel/process.c
--- linux.vanilla/arch/i386/kernel/process.c Sun Jan 24 19:55:30 1999
+++ linux.ac/arch/i386/kernel/process.c Mon Mar 1 00:21:35 1999
@@ -316,7 +316,7 @@
/* Make sure the first page is mapped to the start of physical memory.
It is normally not mapped, to trap kernel NULL pointer dereferences. */
- pg0[0] = 7;
+ pg0[0] = _PAGE_USER | _PAGE_RW | _PAGE_PRESENT;
/*
* Use `swapper_pg_dir' as our page directory. We bother with
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/ptrace.c linux.ac/arch/i386/kernel/ptrace.c
--- linux.vanilla/arch/i386/kernel/ptrace.c Thu Jan 14 01:25:21 1999
+++ linux.ac/arch/i386/kernel/ptrace.c Wed Feb 24 16:38:51 1999
@@ -354,6 +354,7 @@
{
struct task_struct *child;
struct user * dummy = NULL;
+ unsigned long flags;
int i, ret;
lock_kernel();
@@ -391,15 +392,15 @@
if (child->flags & PF_PTRACED)
goto out;
child->flags |= PF_PTRACED;
- if (child->p_pptr != current) {
- unsigned long flags;
- write_lock_irqsave(&tasklist_lock, flags);
+ write_lock_irqsave(&tasklist_lock, flags);
+ if (child->p_pptr != current) {
REMOVE_LINKS(child);
child->p_pptr = current;
SET_LINKS(child);
- write_unlock_irqrestore(&tasklist_lock, flags);
}
+ write_unlock_irqrestore(&tasklist_lock, flags);
+
send_sig(SIGSTOP, child, 1);
ret = 0;
goto out;
@@ -559,7 +560,6 @@
}
case PTRACE_DETACH: { /* detach a process that was attached. */
- unsigned long flags;
long tmp;
ret = -EIO;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/setup.c linux.ac/arch/i386/kernel/setup.c
--- linux.vanilla/arch/i386/kernel/setup.c Tue Feb 23 14:21:32 1999
+++ linux.ac/arch/i386/kernel/setup.c Sat Feb 27 17:18:12 1999
@@ -381,7 +381,17 @@
}
-__initfunc(static int amd_model(struct cpuinfo_x86 *c))
+#define rdmsr(msr,val1,val2) \
+ __asm__ __volatile__("rdmsr" \
+ : "=a" (val1), "=d" (val2) \
+ : "c" (msr))
+
+#define wrmsr(msr,val1,val2) \
+ __asm__ __volatile__("wrmsr" \
+ : /* no outputs */ \
+ : "c" (msr), "a" (val1), "d" (val2))
+
+__initfunc(static int get_model_name(struct cpuinfo_x86 *c))
{
unsigned int n, dummy, *v;
@@ -401,6 +411,76 @@
return 1;
}
+__initfunc(static int amd_model(struct cpuinfo_x86 *c))
+{
+ u32 l, h;
+ unsigned long flags;
+ int mbytes = max_mapnr >> (20-PAGE_SHIFT);
+
+ int r=get_model_name(c);
+
+ /*
+ * Now do the cache operations.
+ */
+
+ switch(c->x86)
+ {
+ case 5:
+ if( c->x86_model < 6 )
+ {
+ /* Anyone with a K5 want to fill this in */
+ break;
+ }
+
+ /* K6 with old style WHCR */
+ if( c->x86_model < 8 ||
+ (c->x86_model== 8 && c->x86_mask < 8))
+ {
+ /* We can only write allocate on the low 508Mb */
+ if(mbytes>508)
+ mbytes=508;
+
+ rdmsr(0xC0000082, l, h);
+ if((l&0x0000FFFF)==0)
+ {
+ l=(1<<0)|(mbytes/4);
+ save_flags(flags);
+ __cli();
+ __asm__ __volatile__ ("wbinvd": : :"memory");
+ wrmsr(0xC0000082, l, h);
+ restore_flags(flags);
+ printk(KERN_INFO "Enabling old style K6 write allocation for %d Mb\n",
+ mbytes);
+
+ }
+ break;
+ }
+ if (c->x86_model == 8 || c->x86_model == 9)
+ {
+ /* The more serious chips .. */
+
+ if(mbytes>4092)
+ mbytes=4092;
+ rdmsr(0xC0000082, l, h);
+ if((l&0xFFFF0000)==0)
+ {
+ l=(mbytes<<22)|(1<<16);
+ save_flags(flags);
+ __cli();
+ __asm__ __volatile__ ("wbinvd": : :"memory");
+ wrmsr(0xC0000082, l, h);
+ restore_flags(flags);
+ printk(KERN_INFO "Enabling new style K6 write allocation for %d Mb\n",
+ mbytes);
+ }
+ break;
+ }
+ break;
+ }
+ return r;
+}
+
+
/*
* Read Cyrix DEVID registers (DIR) to get more detailed info. about the CPU
*/
@@ -517,7 +597,7 @@
/* GXm supports extended cpuid levels 'ala' AMD */
if (c->cpuid_level == 2) {
- amd_model(c); /* get CPU marketing name */
+ get_model_name(c); /* get CPU marketing name */
c->x86_capability&=~X86_FEATURE_TSC;
return;
}
@@ -726,15 +806,6 @@
}
-#define rdmsr(msr,val1,val2) \
- __asm__ __volatile__("rdmsr" \
- : "=a" (val1), "=d" (val2) \
- : "c" (msr))
-
-#define wrmsr(msr,val1,val2) \
- __asm__ __volatile__("wrmsr" \
- : /* no outputs */ \
- : "c" (msr), "a" (val1), "d" (val2))
static char *cpu_vendor_names[] __initdata = {
"Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur" };
@@ -785,8 +856,8 @@
static char *x86_cap_flags[] = {
"fpu", "vme", "de", "pse", "tsc", "msr", "6", "mce",
"cx8", "9", "10", "sep", "12", "pge", "14", "cmov",
- "16", "17", "18", "19", "20", "21", "22", "mmx",
- "24", "25", "26", "27", "28", "29", "30", "31"
+ "16", "17", "snum", "19", "20", "21", "22", "mmx",
+ "24", "kni", "26", "27", "28", "29", "30", "31"
};
struct cpuinfo_x86 *c = cpu_data;
int i, n;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/smp.c linux.ac/arch/i386/kernel/smp.c
--- linux.vanilla/arch/i386/kernel/smp.c Tue Feb 23 14:21:32 1999
+++ linux.ac/arch/i386/kernel/smp.c Mon Mar 1 00:21:35 1999
@@ -474,7 +474,7 @@
*/
cfg=pg0[0];
- pg0[0] = (mp_lapic_addr | 7);
+ pg0[0] = (mp_lapic_addr | _PAGE_USER | _PAGE_RW | _PAGE_PRESENT);
local_flush_tlb();
boot_cpu_id = GET_APIC_ID(*((volatile unsigned long *) APIC_ID));
@@ -1329,7 +1329,7 @@
* Install writable page 0 entry.
*/
cfg = pg0[0];
- pg0[0] = 3; /* writeable, present, addr 0 */
+ pg0[0] = _PAGE_RW | _PAGE_PRESENT; /* writeable, present, addr 0 */
local_flush_tlb();
/*
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/m68k/defconfig linux.ac/arch/m68k/defconfig
--- linux.vanilla/arch/m68k/defconfig Sun Jan 24 19:55:30 1999
+++ linux.ac/arch/m68k/defconfig Fri Feb 26 01:59:54 1999
@@ -78,7 +78,6 @@
CONFIG_PACKET=y
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
-# CONFIG_NET_ALIAS is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
@@ -95,7 +94,6 @@
# (it is safe to leave these untouched)
#
# CONFIG_INET_RARP is not set
-CONFIG_IP_NOSR=y
# CONFIG_SKB_LARGE is not set
# CONFIG_IPV6 is not set
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/m68k/kernel/process.c linux.ac/arch/m68k/kernel/process.c
--- linux.vanilla/arch/m68k/kernel/process.c Sun Jan 24 19:55:31 1999
+++ linux.ac/arch/m68k/kernel/process.c Sun Jan 24 20:22:53 1999
@@ -40,7 +40,6 @@
*/
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
-static struct file * init_fd_array[NR_OPEN] = { NULL, };
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
struct mm_struct init_mm = INIT_MM;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/defconfig linux.ac/arch/mips/defconfig
--- linux.vanilla/arch/mips/defconfig Sun Nov 8 15:08:30 1998
+++ linux.ac/arch/mips/defconfig Fri Feb 26 01:59:54 1999
@@ -90,7 +90,6 @@
# CONFIG_PACKET is not set
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
-# CONFIG_NET_ALIAS is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
@@ -107,7 +106,6 @@
# (it is safe to leave these untouched)
#
# CONFIG_INET_RARP is not set
-CONFIG_IP_NOSR=y
# CONFIG_SKB_LARGE is not set
#
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/init_task.c linux.ac/arch/mips/kernel/init_task.c
--- linux.vanilla/arch/mips/kernel/init_task.c Sun Nov 8 15:08:29 1998
+++ linux.ac/arch/mips/kernel/init_task.c Fri Dec 4 17:14:23 1998
@@ -6,7 +6,6 @@
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
-static struct files * init_fd_array[NR_OPEN] = { NULL, };
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
struct mm_struct init_mm = INIT_MM;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/irixioctl.c linux.ac/arch/mips/kernel/irixioctl.c
--- linux.vanilla/arch/mips/kernel/irixioctl.c Sun Nov 8 15:08:29 1998
+++ linux.ac/arch/mips/kernel/irixioctl.c Fri Dec 4 17:14:23 1998
@@ -33,7 +33,7 @@
{
struct file *filp;
- if(fd >= NR_OPEN || !(filp = current->files->fd[fd]))
+ if(fd >= current->files->max_fds || !(filp = current->files->fd[fd]))
return ((struct tty_struct *) 0);
if(filp->private_data) {
struct tty_struct *ttyp = (struct tty_struct *) filp->private_data;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/sysirix.c linux.ac/arch/mips/kernel/sysirix.c
--- linux.vanilla/arch/mips/kernel/sysirix.c Sun Nov 8 15:10:06 1998
+++ linux.ac/arch/mips/kernel/sysirix.c Fri Dec 4 17:14:23 1998
@@ -788,7 +788,8 @@
error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statfs));
if (error)
goto out;
- if (fd >= NR_OPEN || !(file = current->files->fd[fd])) {
+ if (fd >= current->files->max_fds ||
+ !(file = current->files->fd[fd])) {
error = -EBADF;
goto out;
}
@@ -1111,7 +1112,8 @@
lock_kernel();
if(!(flags & MAP_ANONYMOUS)) {
- if(fd >= NR_OPEN || !(file = current->files->fd[fd])) {
+ if(fd >= current->files->max_fds ||
+ !(file = current->files->fd[fd])) {
retval = -EBADF;
goto out;
}
@@ -1583,7 +1585,8 @@
error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs));
if (error)
goto out;
- if (fd >= NR_OPEN || !(file = current->files->fd[fd])) {
+ if (fd >= current->files->max_fds ||
+ !(file = current->files->fd[fd])) {
error = -EBADF;
goto out;
}
@@ -1727,7 +1730,8 @@
}
if(!(flags & MAP_ANONYMOUS)) {
- if(fd >= NR_OPEN || !(file = current->files->fd[fd])) {
+ if(fd >= current->files->max_fds ||
+ !(file = current->files->fd[fd])) {
error = -EBADF;
goto out;
}
@@ -1879,7 +1883,8 @@
error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs));
if (error)
goto out;
- if (fd >= NR_OPEN || !(file = current->files->fd[fd])) {
+ if (fd >= current->files->max_fds ||
+ !(file = current->files->fd[fd])) {
error = -EBADF;
goto out;
}
@@ -2040,7 +2045,8 @@
current->pid, fd, dirent, count, eob);
#endif
error = -EBADF;
- if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ if (fd >= current->files->max_fds ||
+ !(file = current->files->fd[fd]))
goto out;
dentry = file->f_dentry;
@@ -2151,7 +2157,8 @@
current->pid, fd, dirent, cnt);
#endif
error = -EBADF;
- if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ if (fd >= current->files->max_fds ||
+ !(file = current->files->fd[fd]))
goto out;
dentry = file->f_dentry;
@@ -2212,7 +2219,8 @@
current->pid, fd, dirent, cnt);
#endif
error = -EBADF;
- if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ if (fd >= current->files->max_fds ||
+ !(file = current->files->fd[fd]))
goto out;
dentry = file->f_dentry;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/apus_defconfig linux.ac/arch/ppc/apus_defconfig
--- linux.vanilla/arch/ppc/apus_defconfig Mon Dec 28 23:09:41 1998
+++ linux.ac/arch/ppc/apus_defconfig Fri Feb 26 01:59:54 1999
@@ -100,7 +100,6 @@
# CONFIG_RTNETLINK is not set
# CONFIG_NETLINK_DEV is not set
# CONFIG_FIREWALL is not set
-CONFIG_NET_ALIAS=y
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
@@ -118,7 +117,6 @@
# (it is safe to leave these untouched)
#
CONFIG_INET_RARP=y
-CONFIG_IP_NOSR=y
CONFIG_SKB_LARGE=y
# CONFIG_IPV6 is not set
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/chrp_defconfig linux.ac/arch/ppc/chrp_defconfig
--- linux.vanilla/arch/ppc/chrp_defconfig Mon Dec 28 23:09:41 1998
+++ linux.ac/arch/ppc/chrp_defconfig Fri Feb 26 01:59:54 1999
@@ -85,7 +85,6 @@
# CONFIG_PACKET is not set
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
-CONFIG_NET_ALIAS=y
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
@@ -99,7 +98,6 @@
CONFIG_IP_ALIAS=y
# CONFIG_SYN_COOKIES is not set
CONFIG_INET_RARP=y
-CONFIG_IP_NOSR=y
CONFIG_SKB_LARGE=y
# CONFIG_IPV6 is not set
# CONFIG_IPX is not set
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/common_defconfig linux.ac/arch/ppc/common_defconfig
--- linux.vanilla/arch/ppc/common_defconfig Sat Jan 9 21:50:36 1999
+++ linux.ac/arch/ppc/common_defconfig Fri Feb 26 01:59:54 1999
@@ -87,7 +87,6 @@
# CONFIG_PACKET is not set
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
-# CONFIG_NET_ALIAS is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
@@ -100,7 +99,6 @@
# CONFIG_IP_ALIAS is not set
CONFIG_SYN_COOKIES=y
# CONFIG_INET_RARP is not set
-# CONFIG_IP_NOSR is not set
CONFIG_SKB_LARGE=y
# CONFIG_IPV6 is not set
# CONFIG_IPX is not set
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/defconfig linux.ac/arch/ppc/defconfig
--- linux.vanilla/arch/ppc/defconfig Wed Jan 6 23:02:18 1999
+++ linux.ac/arch/ppc/defconfig Fri Feb 26 01:59:55 1999
@@ -102,7 +102,6 @@
# CONFIG_RTNETLINK is not set
# CONFIG_NETLINK_DEV is not set
# CONFIG_FIREWALL is not set
-CONFIG_NET_ALIAS=y
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
@@ -120,7 +119,6 @@
# (it is safe to leave these untouched)
#
CONFIG_INET_RARP=y
-CONFIG_IP_NOSR=y
CONFIG_SKB_LARGE=y
# CONFIG_IPV6 is not set
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/process.c linux.ac/arch/ppc/kernel/process.c
--- linux.vanilla/arch/ppc/kernel/process.c Sat Jan 9 21:50:36 1999
+++ linux.ac/arch/ppc/kernel/process.c Sat Jan 9 21:57:09 1999
@@ -67,7 +67,6 @@
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
-static struct file * init_fd_array[NR_OPEN] = { NULL, };
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/syscalls.c linux.ac/arch/ppc/kernel/syscalls.c
--- linux.vanilla/arch/ppc/kernel/syscalls.c Sun Nov 8 15:08:33 1998
+++ linux.ac/arch/ppc/kernel/syscalls.c Fri Dec 4 17:14:34 1998
@@ -205,7 +205,8 @@
lock_kernel();
if (!(flags & MAP_ANONYMOUS)) {
- if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ if (fd >= current->files->max_fds ||
+ !(file = current->files->fd[fd]))
goto out;
}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/mbx_defconfig linux.ac/arch/ppc/mbx_defconfig
--- linux.vanilla/arch/ppc/mbx_defconfig Mon Dec 28 23:09:41 1998
+++ linux.ac/arch/ppc/mbx_defconfig Fri Feb 26 01:59:55 1999
@@ -14,7 +14,6 @@
# CONFIG_ALL_PPC is not set
# CONFIG_APUS is not set
CONFIG_MBX=y
-CONFIG_SMP=n
CONFIG_MACH_SPECIFIC=y
CONFIG_SERIAL_CONSOLE=y
@@ -75,7 +74,6 @@
# CONFIG_PACKET is not set
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
-# CONFIG_NET_ALIAS is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
@@ -90,7 +88,6 @@
# CONFIG_IP_ALIAS is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_RARP is not set
-CONFIG_IP_NOSR=y
# CONFIG_SKB_LARGE is not set
# CONFIG_IPV6 is not set
# CONFIG_IPX is not set
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/pmac_defconfig linux.ac/arch/ppc/pmac_defconfig
--- linux.vanilla/arch/ppc/pmac_defconfig Wed Jan 6 23:02:18 1999
+++ linux.ac/arch/ppc/pmac_defconfig Fri Feb 26 01:59:55 1999
@@ -102,7 +102,6 @@
# CONFIG_RTNETLINK is not set
# CONFIG_NETLINK_DEV is not set
# CONFIG_FIREWALL is not set
-CONFIG_NET_ALIAS=y
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
@@ -120,7 +119,6 @@
# (it is safe to leave these untouched)
#
CONFIG_INET_RARP=y
-CONFIG_IP_NOSR=y
CONFIG_SKB_LARGE=y
# CONFIG_IPV6 is not set
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/prep_defconfig linux.ac/arch/ppc/prep_defconfig
--- linux.vanilla/arch/ppc/prep_defconfig Mon Dec 28 23:09:41 1998
+++ linux.ac/arch/ppc/prep_defconfig Fri Feb 26 01:59:55 1999
@@ -84,7 +84,6 @@
# CONFIG_PACKET is not set
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
-# CONFIG_NET_ALIAS is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
@@ -97,7 +96,6 @@
# CONFIG_IP_ALIAS is not set
CONFIG_SYN_COOKIES=y
# CONFIG_INET_RARP is not set
-# CONFIG_IP_NOSR is not set
CONFIG_SKB_LARGE=y
# CONFIG_IPV6 is not set
# CONFIG_IPX is not set
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/defconfig linux.ac/arch/sparc/defconfig
--- linux.vanilla/arch/sparc/defconfig Tue Dec 22 23:19:33 1998
+++ linux.ac/arch/sparc/defconfig Fri Feb 26 01:59:55 1999
@@ -101,7 +101,6 @@
CONFIG_PACKET=y
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
-# CONFIG_NET_ALIAS is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
@@ -118,7 +117,6 @@
# (it is safe to leave these untouched)
#
CONFIG_INET_RARP=m
-CONFIG_IP_NOSR=y
CONFIG_SKB_LARGE=y
CONFIG_IPV6=m
# CONFIG_IPV6_EUI64 is not set
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/kernel/init_task.c linux.ac/arch/sparc/kernel/init_task.c
--- linux.vanilla/arch/sparc/kernel/init_task.c Sun Nov 8 15:10:06 1998
+++ linux.ac/arch/sparc/kernel/init_task.c Fri Dec 4 17:14:35 1998
@@ -6,7 +6,6 @@
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
-static struct file * init_fd_array[NR_OPEN] = { NULL, };
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
struct mm_struct init_mm = INIT_MM;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/defconfig linux.ac/arch/sparc64/defconfig
--- linux.vanilla/arch/sparc64/defconfig Tue Dec 22 23:19:34 1998
+++ linux.ac/arch/sparc64/defconfig Fri Feb 26 01:59:55 1999
@@ -128,7 +128,6 @@
CONFIG_PACKET=y
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
-# CONFIG_NET_ALIAS is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
@@ -145,7 +144,6 @@
# (it is safe to leave these untouched)
#
CONFIG_INET_RARP=m
-CONFIG_IP_NOSR=y
CONFIG_SKB_LARGE=y
CONFIG_IPV6=m
# CONFIG_IPV6_EUI64 is not set
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/init_task.c linux.ac/arch/sparc64/kernel/init_task.c
--- linux.vanilla/arch/sparc64/kernel/init_task.c Sun Nov 8 15:08:40 1998
+++ linux.ac/arch/sparc64/kernel/init_task.c Fri Dec 4 17:14:35 1998
@@ -6,7 +6,6 @@
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
-static struct file * init_fd_array[NR_OPEN] = { NULL, };
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
struct mm_struct init_mm = INIT_MM;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/block/Config.in linux.ac/drivers/acorn/block/Config.in
--- linux.vanilla/drivers/acorn/block/Config.in Sun Nov 8 15:08:19 1998
+++ linux.ac/drivers/acorn/block/Config.in Sun Jan 24 23:54:36 1999
@@ -11,6 +11,7 @@
fi
tristate 'MFM harddisk support' CONFIG_BLK_DEV_MFM
+tristate 'Old Archimedes floppy (1772) support' CONFIG_BLK_DEV_FD1772
if [ "$CONFIG_BLK_DEV_MFM" != "n" ]; then
bool ' Autodetect hard drive geometry' CONFIG_BLK_DEV_MFM_AUTODETECT
fi
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/block/Makefile linux.ac/drivers/acorn/block/Makefile
--- linux.vanilla/drivers/acorn/block/Makefile Sun Nov 8 15:08:19 1998
+++ linux.ac/drivers/acorn/block/Makefile Sun Jan 24 23:54:36 1999
@@ -14,13 +14,11 @@
M_OBJS :=
MOD_LIST_NAME := ACORN_BLOCK_MODULES
-ifeq ($(CONFIG_ARCH_ARC),y)
- ifeq ($(CONFIG_BLK_DEV_FD),y)
- L_OBJS += fd1772.o fd1772dma.o
- else
- ifeq ($(CONFIG_BLK_DEV_FD),m)
- M_OBJS += fd1772_mod.o
- endif
+ifeq ($(CONFIG_BLK_DEV_FD1772),y)
+ L_OBJS += fd1772.o fd1772dma.o
+else
+ ifeq ($(CONFIG_BLK_DEV_FD1772),m)
+ M_OBJS += fd1772_mod.o
endif
endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/block/fd1772.c linux.ac/drivers/acorn/block/fd1772.c
--- linux.vanilla/drivers/acorn/block/fd1772.c Sat Jan 9 21:50:36 1999
+++ linux.ac/drivers/acorn/block/fd1772.c Sun Jan 24 23:54:36 1999
@@ -136,6 +136,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/block/ide-ics.c linux.ac/drivers/acorn/block/ide-ics.c
--- linux.vanilla/drivers/acorn/block/ide-ics.c Tue Dec 22 23:19:34 1998
+++ linux.ac/drivers/acorn/block/ide-ics.c Sun Jan 24 23:54:36 1999
@@ -81,6 +81,8 @@
icside_irqenable_arcin_v5,
icside_irqdisable_arcin_v5,
NULL,
+ NULL,
+ NULL,
NULL
};
@@ -106,9 +108,22 @@
inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
}
+/* Prototype: icside_irqprobe(struct expansion_card *ec)
+ * Purpose : detect an active interrupt from card
+ */
+static int icside_irqpending_arcin_v6(struct expansion_card *ec)
+{
+ unsigned int ide_base_port = (unsigned int)ec->irq_data;
+
+ return inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
+ inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
+}
+
static const expansioncard_ops_t icside_ops_arcin_v6 = {
icside_irqenable_arcin_v6,
icside_irqdisable_arcin_v6,
+ icside_irqpending_arcin_v6,
+ NULL,
NULL,
NULL
};
@@ -220,8 +235,6 @@
case ics_if_arcin_v6:
port = ecard_address (ec, ECARD_IOC, ECARD_FAST);
- ec->irqaddr = ioaddr(port + ICS_ARCIN_V6_INTRSTAT_1);
- ec->irqmask = 1;
ec->irq_data = (void *)port;
ec->ops = (expansioncard_ops_t *)&icside_ops_arcin_v6;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/block/ide-rapide.c linux.ac/drivers/acorn/block/ide-rapide.c
--- linux.vanilla/drivers/acorn/block/ide-rapide.c Sun Nov 8 15:08:19 1998
+++ linux.ac/drivers/acorn/block/ide-rapide.c Sun Jan 24 23:54:36 1999
@@ -13,7 +13,6 @@
#include
#include
#include
-#include
#include "../../block/ide.h"
@@ -28,14 +27,20 @@
static inline int rapide_register(struct expansion_card *ec)
{
unsigned long port = ecard_address (ec, ECARD_MEMC, 0);
- ide_ioregspec_t spec;
+ hw_regs_t hw;
- spec.base = port;
- spec.ctrl = port + 0x206;
- spec.offset = 1 << 4;
- spec.irq = ec->irq;
+ int i;
- return ide_register_port(&spec);
+ memset(&hw, 0, sizeof(hw));
+
+ for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+ hw.io_ports[i] = (ide_ioreg_t)port;
+ port += 1 << 4;
+ }
+ hw.io_ports[IDE_CONTROL_OFFSET] = port + 0x206;
+ hw.irq = ec->irq;
+
+ return ide_register_hw(&hw, NULL);
}
int rapide_init(void)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/block/mfmhd.c linux.ac/drivers/acorn/block/mfmhd.c
--- linux.vanilla/drivers/acorn/block/mfmhd.c Sun Nov 8 15:08:19 1998
+++ linux.ac/drivers/acorn/block/mfmhd.c Sun Jan 24 23:54:36 1999
@@ -123,6 +123,7 @@
#include
#include
#include
+#include
/*
* This sort of stuff should be in a header file shared with ide.c, hd.c, xd.c etc
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/char/Config.in linux.ac/drivers/acorn/char/Config.in
--- linux.vanilla/drivers/acorn/char/Config.in Tue Dec 22 23:19:34 1998
+++ linux.ac/drivers/acorn/char/Config.in Thu Jan 1 01:00:00 1970
@@ -1,15 +0,0 @@
-if [ "$CONFIG_SERIAL" != "n" ]; then
- tristate ' Atomwide serial port support' CONFIG_ATOMWIDE_SERIAL
- tristate ' Dual serial port support' CONFIG_DUALSP_SERIAL
-fi
-
-if [ "$CONFIG_MOUSE" = "y" ]; then
- if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
- if [ "$CONFIG_ARCH_RPC" != "y" ]; then
- define_bool CONFIG_KBDMOUSE y
- else
- define_bool CONFIG_RPCMOUSE y
- fi
- fi
-fi
-
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/char/keyb_ps2.c linux.ac/drivers/acorn/char/keyb_ps2.c
--- linux.vanilla/drivers/acorn/char/keyb_ps2.c Tue Dec 22 23:19:34 1998
+++ linux.ac/drivers/acorn/char/keyb_ps2.c Sun Jan 24 23:54:37 1999
@@ -25,6 +25,7 @@
#include
#include
#include
+#include
#include
extern void kbd_reset_kdown(void);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/char/mouse_rpc.c linux.ac/drivers/acorn/char/mouse_rpc.c
--- linux.vanilla/drivers/acorn/char/mouse_rpc.c Tue Dec 22 23:19:34 1998
+++ linux.ac/drivers/acorn/char/mouse_rpc.c Sun Jan 24 23:54:37 1999
@@ -1,5 +1,5 @@
/*
- * linux/drivers/char/rpcmouse.c
+ * linux/drivers/char/mouse_rpc.c
*
* Copyright (C) 1996-1998 Russell King
*
@@ -16,6 +16,7 @@
#include
#include
#include