Commit d33f1794 authored by Linus Torvalds's avatar Linus Torvalds

Import 2.3.14pre2

parent 6bbf087e
......@@ -10663,6 +10663,33 @@ CONFIG_M68060
If you anticipate running this kernel on a computer with a MC68060
processor, say Y. Otherwise, say N.
Math emulation support
CONFIG_M68KFPU_EMU
At some point in the future, this will cause floating-point math
instructions to be emulated by the kernel on machines that lack a
floating-point math coprocessor. Thrill-seekers and chronically
sleep-deprived psychotic hacker types can say Y now, everyone else
should probably wait a while.
Math emulation only kernel
CONFIG_M68KFPU_EMU_ONLY
This option prevents any floating-point instructions from being
compiled into the kernel, thereby the kernel doesn't save any
floating point context anymore during task switches, so this
kernel will only be usable on machines without a floating-point
math coprocessor. This makes the kernel a bit faster as no tests
needs to be executed whether a floating-point instruction in the
kernel should be executed or not.
Math emulation extra precision
CONFIG_M68KFPU_EMU_EXTRAPREC
The fpu uses normally a few bit more during calculations for
correct rounding, the emulator can (often) do the same but this
extra calculation can cost quite some time, so you can disable
it here. The emulator will then "only" calculate with a 64 bit
mantissa and round slightly incorrect, what is more then enough
for normal usage.
Advanced processor options
CONFIG_ADVANCED_CPU
This gives you access to some advanced options for the CPU. The
......
ISA Plug & Play support by Jaroslav Kysela <perex@suse.cz>
=========================================================
Interface /proc/isapnp
======================
Read commands:
--------------
No comment..
Write commands:
---------------
With the write interface you can simply activate or modify the configuration
for ISA Plug & Play devices. It is mainly useable for drivers which don't
use the ISA Plug & Play kernel support yet.
card <idx> <vendor> - select PnP device by vendor identification
csn <CSN> - select PnP device by CSN
dev <idx> <logdev> - select logical device
auto - run autoconfigure
activate - activate logical device
deactivate - deactivate logical device
port <idx> <value> - set port 0-7 to value
irq <idx> <value> - set IRQ 0-1 to value
dma <idx> <value> - set DMA 0-1 to value
memory <idx> <value> - set memory 0-3 to value
poke <reg> <value> - poke configuration byte to selected register
pokew <reg> <value> - poke configuration word to selected register
poked <reg> <value> - poke configuration dword to selected register
Explanation:
- variable <idx> begins with zero
- variable <CSN> begins with one
- <vendor> is in form 'PNP0000'
- <logdev> is in form 'PNP0000'
Example:
cat > /proc/isapnp <<EOF
card 0 CSC7537
dev 0 CSC0000
port 0 0x534
port 1 0x388
port 2 0x220
irq 0 5
dma 0 1
dma 1 3
poke 0x70 9
activate
logdev 0 CSC0001
port 0 0x240
activate
EOF
Information for developers
==========================
Finding appropriate device
--------------------------
extern struct pci_bus *isapnp_find_card(unsigned short vendor,
unsigned short device,
struct pci_bus *from);
The above function finds a ISA PnP card. For the vendor device should
be used ISAPNP_VENDOR(a,b,c) where a,b,c are characters or integers.
For the device number should be used ISAPNP_DEVICE(x) macro where x is
integer value. Both vendor and device numbers can be get from contents
of the /proc/isapnp file.
extern struct pci_dev *isapnp_find_dev(struct pci_bus *card,
unsigned short vendor,
unsigned short function,
struct pci_dev *from);
The above function finds the ISA PnP device. If card is NULL, then
the global search mode is used (all devices are used for the searching).
Otherwise only devices which belongs to the specified card are verified.
For the function number can be used ISAPNP_FUNCTION(x) macro which works
similarly as the ISAPNP_DEVICE(x) macro.
ISA PnP configuration
=====================
There are two ways how can be ISA PnP interface used.
First way is lowlevel
---------------------
All ISA PNP configuration registers are accessible via lowlevel
isapnp_cfg_(set|get)_(byte|word|dword) functions.
Before any lowlevel function
The function isapnp_cfg_begin() must be called before any lowlevel function.
The function isapnp_cfg_end() must be always called after configuration
otherwise the access to the ISA PnP configuration functions will be blocked.
Second way is auto-configuration
--------------------------------
These two functions gives to the driver the real power of the ISA PnP
feature. First function dev->prepare() only initialize the resource
members in the device structure. This structure contains all resources
set to auto configuration values after the initialization. The driver for
ISA PnP device may modify (or not) some resources to skip auto configuration
for the given resource.
The function isapnp_configure does:
- resources which have the auto configuration value are configured
- the auto configuration is created using ISA PnP resource map
- the function writes configuration to ISA PnP configuration registers
- the function returns to the caller actual used resources
Example (game port initialization)
==================================
/*** initialization ***/
struct pci_dev *dev;
/* find the first game port, use standard PnP IDs */
dev = isapnp_find_dev(NULL,
ISAPNP_VENDOR('P','N','P'),
ISAPNP_FUNCTION(0xb02f),
NULL);
if (!dev)
return -ENODEV;
if (dev->prepare(dev)<0)
return -EAGAIN;
if (!dev->ro) {
/* override resource */
if (user_port != USER_PORT_AUTO_VALUE)
dev->resource[0].start = user_port;
}
if (dev->activate(dev)<0) {
printk("isapnp configure failed (out of resources?)\n");
return -ENOMEM;
}
user_port = dev->resource[0].start; /* get real port */
/*** deactivation ***/
/* to deactivate use: */
if (dev)
dev->deactivate(dev);
......@@ -377,7 +377,7 @@ S: Maintained
HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series
P: Jaroslav Kysela
M: perex@jcu.cz
M: perex@suse.cz
S: Maintained
IBM MCA SCSI SUBSYSTEM DRIVER
......@@ -434,6 +434,11 @@ L: linux-irda@list.uit.no
W: http://www.cs.uit.no/linux-irda/
S: Maintained
ISAPNP
P: Jaroslav Kysela
M: perex@suse.cz
S: Maintained
ISDN SUBSYSTEM
P: Fritz Elfert
M: fritz@wuemaus.franken.de
......
......@@ -71,7 +71,8 @@
mv_writew: CAT(low1,_writew), \
mv_writel: CAT(low1,_writel), \
mv_writeq: CAT(low1,_writeq), \
mv_dense_mem: CAT(low2,_dense_mem)
mv_ioremap: CAT(low2,_ioremap), \
mv_is_ioaddr: CAT(low2,_is_ioaddr)
#define IO(UP,low1,low2) \
IO_LITE(UP,low1,low2), \
......
......@@ -37,45 +37,96 @@ void _outl(unsigned int b, unsigned long addr)
__outl(b, addr);
}
unsigned long ___raw_readb(unsigned long addr)
{
return __readb(addr);
}
unsigned long ___raw_readw(unsigned long addr)
{
return __readw(addr);
}
unsigned long ___raw_readl(unsigned long addr)
{
return __readl(addr);
}
unsigned long ___raw_readq(unsigned long addr)
{
return __readq(addr);
}
unsigned long _readb(unsigned long addr)
{
return __readb(addr);
unsigned long r = __readb(addr);
mb();
return r;
}
unsigned long _readw(unsigned long addr)
{
return __readw(addr);
unsigned long r = __readw(addr);
mb();
return r;
}
unsigned long _readl(unsigned long addr)
{
return __readl(addr);
unsigned long r = __readl(addr);
mb();
return r;
}
unsigned long _readq(unsigned long addr)
{
return __readq(addr);
unsigned long r = __readq(addr);
mb();
return r;
}
void ___raw_writeb(unsigned char b, unsigned long addr)
{
__writeb(b, addr);
}
void ___raw_writeb(unsigned short b, unsigned long addr)
{
__writew(b, addr);
}
void ___raw_writel(unsigned int b, unsigned long addr)
{
__writel(b, addr);
}
void ___raw_writeq(unsigned long b, unsigned long addr)
{
__writeq(b, addr);
}
void _writeb(unsigned char b, unsigned long addr)
{
__writeb(b, addr);
mb();
}
void _writew(unsigned short b, unsigned long addr)
{
__writew(b, addr);
mb();
}
void _writel(unsigned int b, unsigned long addr)
{
__writel(b, addr);
mb();
}
void _writeq(unsigned long b, unsigned long addr)
{
__writeq(b, addr);
mb();
}
/*
......@@ -363,7 +414,7 @@ void _memcpy_fromio(void * to, unsigned long from, long count)
if (count >= 8 && ((long)to & 7) == (from & 7)) {
count -= 8;
do {
*(u64 *)to = readq(from);
*(u64 *)to = __raw_readq(from);
count -= 8;
to += 8;
from += 8;
......@@ -374,7 +425,7 @@ void _memcpy_fromio(void * to, unsigned long from, long count)
if (count >= 4 && ((long)to & 3) == (from & 3)) {
count -= 4;
do {
*(u32 *)to = readl(from);
*(u32 *)to = __raw_readl(from);
count -= 4;
to += 4;
from += 4;
......@@ -385,7 +436,7 @@ void _memcpy_fromio(void * to, unsigned long from, long count)
if (count >= 2 && ((long)to & 1) == (from & 1)) {
count -= 2;
do {
*(u16 *)to = readw(from);
*(u16 *)to = __raw_readw(from);
count -= 2;
to += 2;
from += 2;
......@@ -394,7 +445,7 @@ void _memcpy_fromio(void * to, unsigned long from, long count)
}
while (count > 0) {
*(u8 *) to = readb(from);
*(u8 *) to = __raw_readb(from);
count--;
to++;
from++;
......@@ -414,7 +465,7 @@ void _memcpy_toio(unsigned long to, const void * from, long count)
if (count >= 8 && (to & 7) == ((long)from & 7)) {
count -= 8;
do {
writeq(*(const u64 *)from, to);
__raw_writeq(*(const u64 *)from, to);
count -= 8;
to += 8;
from += 8;
......@@ -425,7 +476,7 @@ void _memcpy_toio(unsigned long to, const void * from, long count)
if (count >= 4 && (to & 3) == ((long)from & 3)) {
count -= 4;
do {
writel(*(const u32 *)from, to);
__raw_writel(*(const u32 *)from, to);
count -= 4;
to += 4;
from += 4;
......@@ -436,7 +487,7 @@ void _memcpy_toio(unsigned long to, const void * from, long count)
if (count >= 2 && (to & 1) == ((long)from & 1)) {
count -= 2;
do {
writew(*(const u16 *)from, to);
__raw_writeb(*(const u16 *)from, to);
count -= 2;
to += 2;
from += 2;
......@@ -445,11 +496,12 @@ void _memcpy_toio(unsigned long to, const void * from, long count)
}
while (count > 0) {
writeb(*(const u8 *) from, to);
__raw_writeb(*(const u8 *) from, to);
count--;
to++;
from++;
}
mb();
}
/*
......@@ -459,21 +511,21 @@ void _memset_c_io(unsigned long to, unsigned long c, long count)
{
/* Handle any initial odd byte */
if (count > 0 && (to & 1)) {
writeb(c, to);
__raw_writeb(c, to);
to++;
count--;
}
/* Handle any initial odd halfword */
if (count >= 2 && (to & 2)) {
writew(c, to);
__raw_writeb(c, to);
to += 2;
count -= 2;
}
/* Handle any initial odd word */
if (count >= 4 && (to & 4)) {
writel(c, to);
__raw_writel(c, to);
to += 4;
count -= 4;
}
......@@ -483,7 +535,7 @@ void _memset_c_io(unsigned long to, unsigned long c, long count)
count -= 8;
if (count >= 0) {
do {
writeq(c, to);
__raw_writeq(c, to);
to += 8;
count -= 8;
} while (count >= 0);
......@@ -492,20 +544,21 @@ void _memset_c_io(unsigned long to, unsigned long c, long count)
/* The tail is word-aligned if we still have count >= 4 */
if (count >= 4) {
writel(c, to);
__raw_writel(c, to);
to += 4;
count -= 4;
}
/* The tail is half-word aligned if we have count >= 2 */
if (count >= 2) {
writew(c, to);
__raw_writeb(c, to);
to += 2;
count -= 2;
}
/* And finally, one last byte.. */
if (count) {
writeb(c, to);
__raw_writeb(c, to);
}
mb();
}
......@@ -69,6 +69,12 @@ CONFIG_BINFMT_MISC=y
# CONFIG_I2O_SCSI is not set
# CONFIG_I2O_PROC is not set
#
# Plug and Play configuration
#
CONFIG_PNP=y
CONFIG_ISAPNP=y
#
# Block devices
#
......
......@@ -93,7 +93,7 @@ extern int rd_image_start; /* starting block # of image */
#endif
extern int root_mountflags;
extern int _etext, _edata, _end;
extern int _text, _etext, _edata, _end;
extern unsigned long cpu_hz;
/*
......@@ -251,7 +251,7 @@ visws_get_board_type_and_rev(void)
static char command_line[COMMAND_LINE_SIZE] = { 0, };
char saved_command_line[COMMAND_LINE_SIZE];
struct resource standard_resources[] = {
struct resource standard_io_resources[] = {
{ "dma1", 0x00, 0x1f },
{ "pic1", 0x20, 0x3f },
{ "timer", 0x40, 0x5f },
......@@ -262,14 +262,90 @@ struct resource standard_resources[] = {
{ "fpu", 0xf0, 0xff }
};
/* For demonstration purposes only.. */
#define keyboard_resources (standard_resources+3)
struct resource kbd_status_resource = { "status", 0x60, 0x60 };
#define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource))
/* System RAM - interrupted by the 640kB-1M hole */
#define code_resource (ram_resources[3])
#define data_resource (ram_resources[4])
static struct resource ram_resources[] = {
{ "System RAM", 0x000000, 0x09ffff, IORESOURCE_BUSY },
{ "System RAM", 0x100000, 0x100000, IORESOURCE_BUSY },
{ "Video RAM area", 0x0a0000, 0x0bffff },
{ "Kernel code", 0x100000, 0 },
{ "Kernel data", 0, 0 }
};
/* System ROM resources */
#define MAXROMS 6
static struct resource rom_resources[MAXROMS] = {
{ "System ROM", 0xF0000, 0xFFFFF, IORESOURCE_BUSY },
{ "Video ROM", 0xc0000, 0xc7fff }
};
#define romsignature(x) (*(unsigned short *)(x) == 0xaa55)
static void __init probe_roms(void)
{
int roms = 1;
unsigned long base;
unsigned char *romstart;
request_resource(&iomem_resource, rom_resources+0);
/* Video ROM is standard at C000:0000 - C7FF:0000, check signature */
for (base = 0xC0000; base < 0xE0000; base += 2048) {
romstart = bus_to_virt(base);
if (!romsignature(romstart))
continue;
request_resource(&iomem_resource, rom_resources + roms);
roms++;
break;
}
/* Extension roms at C800:0000 - DFFF:0000 */
for (base = 0xC8000; base < 0xE0000; base += 2048) {
unsigned long length;
#define STANDARD_RESOURCES (sizeof(standard_resources)/sizeof(struct resource))
romstart = bus_to_virt(base);
if (!romsignature(romstart))
continue;
length = romstart[2] * 512;
if (length) {
unsigned int i;
unsigned char chksum;
chksum = 0;
for (i = 0; i < length; i++)
chksum += romstart[i];
/* Good checksum? */
if (!chksum) {
rom_resources[roms].start = base;
rom_resources[roms].end = base + length - 1;
rom_resources[roms].name = "Extension ROM";
request_resource(&iomem_resource, rom_resources + roms);
roms++;
if (roms >= MAXROMS)
return;
}
}
}
/* Final check for motherboard extension rom at E000:0000 */
base = 0xE0000;
romstart = bus_to_virt(base);
if (romsignature(romstart)) {
rom_resources[roms].start = base;
rom_resources[roms].end = base + 65535;
rom_resources[roms].name = "Extension ROM";
__initfunc(void setup_arch(char **cmdline_p,
unsigned long * memory_start_p, unsigned long * memory_end_p))
request_resource(&iomem_resource, rom_resources + roms);
}
}
void __init setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p)
{
unsigned long memory_start, memory_end;
char c = ' ', *to = command_line, *from = COMMAND_LINE;
......@@ -301,6 +377,8 @@ __initfunc(void setup_arch(char **cmdline_p,
}
#endif
ram_resources[1].end = memory_end-1;
memory_end &= PAGE_MASK;
#ifdef CONFIG_BLK_DEV_RAM
rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
......@@ -310,11 +388,16 @@ __initfunc(void setup_arch(char **cmdline_p,
if (!MOUNT_ROOT_RDONLY)
root_mountflags &= ~MS_RDONLY;
memory_start = (unsigned long) &_end;
init_mm.start_code = PAGE_OFFSET;
init_mm.start_code = (unsigned long) &_text;
init_mm.end_code = (unsigned long) &_etext;
init_mm.end_data = (unsigned long) &_edata;
init_mm.brk = (unsigned long) &_end;
code_resource.start = virt_to_bus(&_text);
code_resource.end = virt_to_bus(&_etext)-1;
data_resource.start = virt_to_bus(&_etext);
data_resource.end = virt_to_bus(&_edata)-1;
/* Save unparsed command line copy for /proc/cmdline */
memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
......@@ -339,6 +422,8 @@ __initfunc(void setup_arch(char **cmdline_p,
memory_end = memory_end << 20;
from++;
}
if (memory_end > ram_resources[1].end)
ram_resources[1].end = memory_end-1;
}
}
c = *(from++);
......@@ -351,6 +436,14 @@ __initfunc(void setup_arch(char **cmdline_p,
*to = '\0';
*cmdline_p = command_line;
/* Request the standard RAM and ROM resources - they eat up PCI memory space */
request_resource(&iomem_resource, ram_resources+0);
request_resource(&iomem_resource, ram_resources+1);
request_resource(&iomem_resource, ram_resources+2);
request_resource(ram_resources+1, &code_resource);
request_resource(ram_resources+1, &data_resource);
probe_roms();
#define VMALLOC_RESERVE (128 << 20) /* 128MB for vmalloc and initrd */
#define MAXMEM ((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE))
......@@ -386,9 +479,8 @@ __initfunc(void setup_arch(char **cmdline_p,
#endif
/* request I/O space for devices used on all i[345]86 PCs */
for (i = 0; i < STANDARD_RESOURCES; i++)
request_resource(&ioport_resource, standard_resources+i);
request_resource(keyboard_resources, &kbd_status_resource);
for (i = 0; i < STANDARD_IO_RESOURCES; i++)
request_resource(&ioport_resource, standard_io_resources+i);
#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
......
......@@ -116,6 +116,11 @@ CORE_FILES := $(CORE_FILES) arch/m68k/ifpsp060/ifpsp.o
SUBDIRS := $(SUBDIRS) arch/m68k/ifpsp060
endif
ifdef CONFIG_M68KFPU_EMU
CORE_FILES := $(CORE_FILES) arch/m68k/math-emu/mathemu.o
SUBDIRS := $(SUBDIRS) arch/m68k/math-emu
endif
lilo: vmlinux
if [ -f $(INSTALL_PATH)/vmlinux ]; then mv -f $(INSTALL_PATH)/vmlinux $(INSTALL_PATH)/vmlinux.old; fi
if [ -f $(INSTALL_PATH)/System.map ]; then mv -f $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
......
......@@ -19,6 +19,20 @@
* called again.
* The whole interrupt handling for CIAs is moved to cia.c
* /Roman Zippel
*
* 07/08/99: rewamp of the interrupt handling - we now have two types of
* interrupts, normal and fast handlers, fast handlers being
* marked with SA_INTERRUPT and runs with all other interrupts
* disabled. Normal interrupts disable their own source but
* run with all other interrupt sources enabled.
* PORTS and EXTER interrupts are always shared even if the
* drivers do not explicitly mark this when calling
* request_irq which they really should do.
* This is similar to the way interrupts are handled on all
* other architectures and makes a ton of sense besides
* having the advantage of making it easier to share
* drivers.
* /Jes
*/
#include <linux/types.h>
......@@ -70,7 +84,7 @@ static void ami_badint(int irq, void *dev_id, struct pt_regs *fp)
* the amiga IRQ handling routines.
*/
__initfunc(void amiga_init_IRQ(void))
void __init amiga_init_IRQ(void)
{
int i;
......@@ -81,7 +95,7 @@ __initfunc(void amiga_init_IRQ(void))
} else {
ami_irq_list[i] = new_irq_node();
ami_irq_list[i]->handler = ami_badint;
ami_irq_list[i]->flags = IRQ_FLG_STD;
ami_irq_list[i]->flags = 0;
ami_irq_list[i]->dev_id = NULL;
ami_irq_list[i]->devname = NULL;
ami_irq_list[i]->next = NULL;
......@@ -117,19 +131,18 @@ static inline void amiga_insert_irq(irq_node_t **list, irq_node_t *node)
cur = *list;
if (node->flags & IRQ_FLG_FAST) {
node->flags &= ~IRQ_FLG_SLOW;
while (cur && cur->flags & IRQ_FLG_FAST) {
list = &cur->next;
cur = cur->next;
}
} else if (node->flags & IRQ_FLG_SLOW) {
while (cur) {
if (node->flags & SA_INTERRUPT) {
if (node->flags & SA_SHIRQ)
return;
/*
* There should never be more than one
*/
while (cur && cur->flags & SA_INTERRUPT) {
list = &cur->next;
cur = cur->next;
}
} else {
while (cur && !(cur->flags & IRQ_FLG_SLOW)) {
while (cur) {
list = &cur->next;
cur = cur->next;
}
......@@ -168,13 +181,15 @@ static inline void amiga_delete_irq(irq_node_t **list, void *dev_id)
* If the addition was successful, it returns 0.
*/
int amiga_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
int amiga_request_irq(unsigned int irq,
void (*handler)(int, void *, struct pt_regs *),
unsigned long flags, const char *devname, void *dev_id)
{
irq_node_t *node;
if (irq >= AMI_IRQS) {
printk ("%s: Unknown IRQ %d from %s\n", __FUNCTION__, irq, devname);
printk ("%s: Unknown IRQ %d from %s\n", __FUNCTION__,
irq, devname);
return -ENXIO;
}
......@@ -190,6 +205,11 @@ int amiga_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_r
return cia_request_irq(&ciaa_base, irq - IRQ_AMIGA_CIAA,
handler, flags, devname, dev_id);
/*
* IRQ_AMIGA_PORTS & IRQ_AMIGA_EXTER defaults to shared,
* we could add a check here for the SA_SHIRQ flag but all drivers
* should be aware of sharing anyway.
*/
if (ami_servers[irq]) {
if (!(node = new_irq_node()))
return -ENOMEM;
......@@ -200,18 +220,6 @@ int amiga_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_r
node->next = NULL;
amiga_insert_irq(&ami_irq_list[irq], node);
} else {
if (!(ami_irq_list[irq]->flags & IRQ_FLG_STD)) {
if (ami_irq_list[irq]->flags & IRQ_FLG_LOCK) {
printk("%s: IRQ %d from %s is not replaceable\n",
__FUNCTION__, irq, ami_irq_list[irq]->devname);
return -EBUSY;
}
if (!(flags & IRQ_FLG_REPLACE)) {
printk("%s: %s can't replace IRQ %d from %s\n",
__FUNCTION__, devname, irq, ami_irq_list[irq]->devname);
return -EBUSY;
}
}
ami_irq_list[irq]->handler = handler;
ami_irq_list[irq]->flags = flags;
ami_irq_list[irq]->dev_id = dev_id;
......@@ -255,7 +263,7 @@ void amiga_free_irq(unsigned int irq, void *dev_id)
printk("%s: removing probably wrong IRQ %d from %s\n",
__FUNCTION__, irq, ami_irq_list[irq]->devname);
ami_irq_list[irq]->handler = ami_badint;
ami_irq_list[irq]->flags = IRQ_FLG_STD;
ami_irq_list[irq]->flags = 0;
ami_irq_list[irq]->dev_id = NULL;
ami_irq_list[irq]->devname = NULL;
custom.intena = ami_intena_vals[irq];
......@@ -345,37 +353,58 @@ inline void amiga_do_irq(int irq, struct pt_regs *fp)
void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server)
{
irq_node_t *node, *slow_nodes;
unsigned short flags;
unsigned short flags, intena;
kstat.irqs[0][SYS_IRQS + irq]++;
if (server->count++)
server->reentrance = 1;
/* serve first fast and normal handlers */
for (node = ami_irq_list[irq];
node && (!(node->flags & IRQ_FLG_SLOW));
node = node->next)
node->handler(irq, node->dev_id, fp);
custom.intreq = ami_intena_vals[irq];
intena = ami_intena_vals[irq];
custom.intreq = intena;
/* serve first fast handlers - there can only be one of these */
node = ami_irq_list[irq];
/*
* Timer interrupts show up like this
*/
if (!node) {
server->count--;
return;
}
if (node && (node->flags & SA_INTERRUPT)) {
save_flags(flags);
cli();
node->handler(irq, node->dev_id, fp);
restore_flags(flags);
server->count--;
return;
}
/*
* Disable the interrupt source in question and reenable all
* other interrupts. No interrupt handler should ever touch
* the intena flags directly!
*/
custom.intena = intena;
save_flags(flags);
restore_flags((flags & ~0x0700) | (fp->sr & 0x0700));
/* if slow handlers exists, serve them now */
sti();
slow_nodes = node;
for (;;) {
for (; node; node = node->next)
node->handler(irq, node->dev_id, fp);
/* if reentrance occurred, serve slow handlers again */
custom.intena = ami_intena_vals[irq];
if (!server->reentrance) {
server->count--;
custom.intena = IF_SETCLR | ami_intena_vals[irq];
restore_flags(flags);
custom.intena = IF_SETCLR | intena;
return;
}
server->reentrance = 0;
custom.intena = IF_SETCLR | ami_intena_vals[irq];
node = slow_nodes;
}
}
......@@ -493,24 +522,13 @@ int amiga_get_irq_list(char *buf)
for (i = 0; i < AMI_STD_IRQS; i++) {
if (!(node = ami_irq_list[i]))
continue;
if (node->flags & IRQ_FLG_STD)
continue;
len += sprintf(buf+len, "ami %2d: %10u ", i,
kstat.irqs[0][SYS_IRQS + i]);
do {
if (ami_servers[i]) {
if (node->flags & IRQ_FLG_FAST)
len += sprintf(buf+len, "F ");
else if (node->flags & IRQ_FLG_SLOW)
len += sprintf(buf+len, "S ");
else
len += sprintf(buf+len, " ");
} else {
if (node->flags & IRQ_FLG_LOCK)
len += sprintf(buf+len, "L ");
else
len += sprintf(buf+len, " ");
}
if (node->flags & SA_INTERRUPT)
len += sprintf(buf+len, "F ");
else
len += sprintf(buf+len, " ");
len += sprintf(buf+len, "%s\n", node->devname);
if ((node = node->next))
len += sprintf(buf+len, " ");
......
......@@ -94,20 +94,6 @@ int cia_request_irq(struct ciabase *base, unsigned int irq,
{
u_char mask;
if (!(base->irq_list[irq].flags & IRQ_FLG_STD)) {
if (base->irq_list[irq].flags & IRQ_FLG_LOCK) {
printk("%s: IRQ %i from %s is not replaceable\n",
__FUNCTION__, base->cia_irq + irq,
base->irq_list[irq].devname);
return -EBUSY;
}
if (!(flags & IRQ_FLG_REPLACE)) {
printk("%s: %s can't replace IRQ %i from %s\n", __FUNCTION__,
devname, base->cia_irq + irq,
base->irq_list[irq].devname);
return -EBUSY;
}
}
base->irq_list[irq].handler = handler;
base->irq_list[irq].flags = flags;
base->irq_list[irq].dev_id = dev_id;
......@@ -128,7 +114,7 @@ void cia_free_irq(struct ciabase *base, unsigned int irq, void *dev_id)
base->irq_list[irq].devname);
base->irq_list[irq].handler = NULL;
base->irq_list[irq].flags = IRQ_FLG_STD;
base->irq_list[irq].flags = 0;
cia_able_irq(base, 1 << irq);
}
......@@ -153,14 +139,14 @@ static void cia_handler(int irq, void *dev_id, struct pt_regs *fp)
amiga_do_irq_list(base->server_irq, fp, &base->server);
}
__initfunc(void cia_init_IRQ(struct ciabase *base))
void __init cia_init_IRQ(struct ciabase *base)
{
int i;
/* init isr handlers */
for (i = 0; i < CIA_IRQS; i++) {
base->irq_list[i].handler = NULL;
base->irq_list[i].flags = IRQ_FLG_STD;
base->irq_list[i].flags = 0;
}
/* clear any pending interrupt and turn off all interrupts */
......@@ -168,7 +154,7 @@ __initfunc(void cia_init_IRQ(struct ciabase *base))
cia_able_irq(base, CIA_ICR_ALL);
/* install CIA handler */
request_irq(base->handler_irq, cia_handler, IRQ_FLG_LOCK, base->name, base);
request_irq(base->handler_irq, cia_handler, 0, base->name, base);
custom.intena = IF_SETCLR | base->int_mask;
}
......@@ -179,15 +165,10 @@ int cia_get_irq_list(struct ciabase *base, char *buf)
j = base->cia_irq;
for (i = 0; i < CIA_IRQS; i++) {
if (!(base->irq_list[i].flags & IRQ_FLG_STD)) {
len += sprintf(buf+len, "cia %2d: %10d ", j + i,
kstat.irqs[0][SYS_IRQS + j + i]);
if (base->irq_list[i].flags & IRQ_FLG_LOCK)
len += sprintf(buf+len, "L ");
else
len += sprintf(buf+len, " ");
len += sprintf(buf+len, "%s\n", base->irq_list[i].devname);
}
len += sprintf(buf+len, "cia %2d: %10d ", j + i,
kstat.irqs[0][SYS_IRQS + j + i]);
len += sprintf(buf+len, " ");
len += sprintf(buf+len, "%s\n", base->irq_list[i].devname);
}
return len;
}
......@@ -173,7 +173,7 @@ int amiga_parse_bootinfo(const struct bi_record *record)
* Identify builtin hardware
*/
__initfunc(static void amiga_identify(void))
static void __init amiga_identify(void)
{
/* Fill in some default values, if necessary */
if (amiga_eclock == 0)
......@@ -334,7 +334,7 @@ __initfunc(static void amiga_identify(void))
* Setup the Amiga configuration info
*/
__initfunc(void config_amiga(void))
void __init config_amiga(void)
{
amiga_debug_init();
amiga_identify();
......@@ -446,8 +446,8 @@ __initfunc(void config_amiga(void))
static unsigned short jiffy_ticks;
__initfunc(static void amiga_sched_init(void (*timer_routine)(int, void *,
struct pt_regs *)))
static void __init amiga_sched_init(void (*timer_routine)(int, void *,
struct pt_regs *))
{
jiffy_ticks = (amiga_eclock+HZ/2)/HZ;
......@@ -460,8 +460,7 @@ __initfunc(static void amiga_sched_init(void (*timer_routine)(int, void *,
* Please don't change this to use ciaa, as it interferes with the
* SCSI code. We'll have to take a look at this later
*/
request_irq(IRQ_AMIGA_CIAB_TA, timer_routine, IRQ_FLG_LOCK,
"timer", NULL);
request_irq(IRQ_AMIGA_CIAB_TA, timer_routine, 0, "timer", NULL);
/* start timer */
ciab.cra |= 0x11;
}
......@@ -880,7 +879,7 @@ void amiga_serial_gets(struct console *co, char *s, int len)
}
#endif
__initfunc(static void amiga_debug_init(void))
static void __init amiga_debug_init(void)
{
if (!strcmp( m68k_debug_device, "ser" )) {
/* no initialization required (?) */
......
......@@ -58,6 +58,13 @@ bool '68020 support' CONFIG_M68020
bool '68030 support' CONFIG_M68030
bool '68040 support' CONFIG_M68040
bool '68060 support' CONFIG_M68060
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool 'Math emulation support' CONFIG_M68KFPU_EMU
if [ "$CONFIG_M68KFPU_EMU" = "y" ]; then
bool 'Math emulation extra precision' CONFIG_M68KFPU_EMU_EXTRAPREC
bool 'Math emulation only kernel' CONFIG_M68KFPU_EMU_ONLY
fi
fi
bool 'Advanced configuration options' CONFIG_ADVANCED
if [ "$CONFIG_ADVANCED" = "y" ]; then
bool 'Use read-modify-write instructions' CONFIG_RMW_INSNS
......
......@@ -164,6 +164,36 @@ do_delayed_trace:
addql #4,%sp
jra 5b
#if 0
#if CONFIG_AMIGA
SYMBOL_NAME_LABEL(ami_inthandler)
addql #1,SYMBOL_NAME(local_irq_count)
SAVE_ALL_INT
GET_CURRENT(%d0)
bfextu %sp@(PT_VECTOR){#4,#12},%d0
movel %d0,%a0
addql #1,%a0@(SYMBOL_NAME(kstat)+STAT_IRQ-VECOFF(VEC_SPUR))
movel %a0@(SYMBOL_NAME(autoirq_list)-VECOFF(VEC_SPUR)),%a0
| amiga vector int handler get the req mask instead of irq vector
lea CUSTOMBASE,%a1
movew %a1@(C_INTREQR),%d0
andw %a1@(C_INTENAR),%d0
| prepare stack (push frame pointer, dev_id & req mask)
pea %sp@
movel %a0@(IRQ_DEVID),%sp@-
movel %d0,%sp@-
pea %pc@(SYMBOL_NAME(ret_from_interrupt):w)
jbra @(IRQ_HANDLER,%a0)@(0)
ENTRY(nmi_handler)
rte
#endif
#endif
/*
** This is the main interrupt handler, responsible for calling process_int()
*/
......@@ -183,7 +213,7 @@ SYMBOL_NAME_LABEL(inthandler)
jbeq 1f
jbsr SYMBOL_NAME(floppy_hardint)
jbra 3f
1:
1:
#endif
jbsr SYMBOL_NAME(process_int)| process the IRQ
3: addql #8,%sp | pop parameters off stack
......@@ -191,7 +221,7 @@ SYMBOL_NAME_LABEL(inthandler)
SYMBOL_NAME_LABEL(ret_from_interrupt)
subql #1,SYMBOL_NAME(local_irq_count)
jeq 1f
2:
2:
RESTORE_ALL
1:
#if 1
......@@ -295,6 +325,11 @@ SYMBOL_NAME_LABEL(resume)
movel %sp,%a0@(TASK_THREAD+THREAD_KSP)
/* save floating point context */
#ifndef CONFIG_M68KFPU_EMU_ONLY
#ifdef CONFIG_M68KFPU_EMU
tstl SYMBOL_NAME(m68k_fputype)
jeq 3f
#endif
fsave %a0@(TASK_THREAD+THREAD_FPSTATE)
#if defined(CONFIG_M68060)
......@@ -316,6 +351,7 @@ SYMBOL_NAME_LABEL(resume)
2: fmovemx %fp0-%fp7,%a0@(TASK_THREAD+THREAD_FPREG)
fmoveml %fpcr/%fpsr/%fpiar,%a0@(TASK_THREAD+THREAD_FPCNTL)
3:
#endif /* CONFIG_M68KFPU_EMU_ONLY */
/* Return previous task in %d1 */
movel %curptr,%d1
......@@ -323,7 +359,11 @@ SYMBOL_NAME_LABEL(resume)
movel %a1,%curptr
/* restore floating point context */
#ifndef CONFIG_M68KFPU_EMU_ONLY
#ifdef CONFIG_M68KFPU_EMU
tstl SYMBOL_NAME(m68k_fputype)
jeq 4f
#endif
#if defined(CONFIG_M68060)
#if !defined(CPU_M68060_ONLY)
btst #3,SYMBOL_NAME(m68k_cputype)+3
......@@ -343,6 +383,8 @@ SYMBOL_NAME_LABEL(resume)
2: fmovemx %a1@(TASK_THREAD+THREAD_FPREG),%fp0-%fp7
fmoveml %a1@(TASK_THREAD+THREAD_FPCNTL),%fpcr/%fpsr/%fpiar
3: frestore %a1@(TASK_THREAD+THREAD_FPSTATE)
4:
#endif /* CONFIG_M68KFPU_EMU_ONLY */
/* restore the kernel stack pointer */
movel %a1@(TASK_THREAD+THREAD_KSP),%sp
......
......@@ -503,10 +503,18 @@ func_define putn,1
.macro puts string
#if defined(CONSOLE) || defined(SERIAL_DEBUG)
/* The __INITDATA stuff is a no-op when ftrace or kgdb are turned on */
#if defined(CONFIG_FTRACE) || defined(CONFIG_KGDB)
bra 1f
#endif
__INITDATA
.Lstr\@:
.string "\string"
__FINIT
#if defined(CONFIG_FTRACE) || defined(CONFIG_KGDB)
.align 2
1:
#endif
pea %pc@(.Lstr\@)
func_call puts
addql #4,%sp
......
......@@ -86,14 +86,14 @@ void (*mach_free_irq) (unsigned int, void *) = dummy_free_irq;
* the IRQ handling routines.
*/
__initfunc(void init_IRQ(void))
void __init init_IRQ(void)
{
int i;
for (i = 0; i < SYS_IRQS; i++) {
if (mach_default_handler)
irq_list[i].handler = (*mach_default_handler)[i];
irq_list[i].flags = IRQ_FLG_STD;
irq_list[i].flags = 0;
irq_list[i].dev_id = NULL;
irq_list[i].devname = default_names[i];
}
......@@ -144,6 +144,7 @@ int sys_request_irq(unsigned int irq,
return -ENXIO;
}
#if 0
if (!(irq_list[irq].flags & IRQ_FLG_STD)) {
if (irq_list[irq].flags & IRQ_FLG_LOCK) {
printk("%s: IRQ %d from %s is not replaceable\n",
......@@ -156,6 +157,8 @@ int sys_request_irq(unsigned int irq,
return -EBUSY;
}
}
#endif
irq_list[irq].handler = handler;
irq_list[irq].flags = flags;
irq_list[irq].dev_id = dev_id;
......@@ -175,7 +178,7 @@ void sys_free_irq(unsigned int irq, void *dev_id)
__FUNCTION__, irq, irq_list[irq].devname);
irq_list[irq].handler = (*mach_default_handler)[irq];
irq_list[irq].flags = IRQ_FLG_STD;
irq_list[irq].flags = 0;
irq_list[irq].dev_id = NULL;
irq_list[irq].devname = default_names[irq];
}
......@@ -250,9 +253,6 @@ int get_irq_list(char *buf)
for (i = 0; i < SYS_IRQS; i++) {
len += sprintf(buf+len, "auto %2d: %10u ", i,
i ? kstat.irqs[0][i] : num_spurious);
if (irq_list[i].flags & IRQ_FLG_LOCK)
len += sprintf(buf+len, "L ");
else
len += sprintf(buf+len, " ");
len += sprintf(buf+len, "%s\n", irq_list[i].devname);
}
......
......@@ -7,19 +7,29 @@
#define TASK_FLAGS 4
#define TASK_SIGPENDING 8
#define TASK_NEEDRESCHED 20
#define TASK_TSS 470
#define TASK_MM 622
#define TSS_KSP 0
#define TSS_USP 4
#define TSS_SR 8
#define TSS_FS 10
#define TSS_CRP 12
#define TSS_ESP0 20
#define TSS_FPREG 24
#define TSS_FPCNTL 120
#define TSS_FPSTATE 132
#define TASK_THREAD 482
#define TASK_MM 634
#define TASK_ACTIVE_MM 638
#define THREAD_KSP 0
#define THREAD_USP 4
#define THREAD_SR 8
#define THREAD_FS 10
#define THREAD_CRP 12
#define THREAD_ESP0 20
#define THREAD_FPREG 24
#define THREAD_FPCNTL 120
#define THREAD_FPSTATE 132
#define PT_D0 32
#define PT_ORIG_D0 36
#define PT_D1 0
#define PT_D2 4
#define PT_D3 8
#define PT_D4 12
#define PT_D5 16
#define PT_A0 20
#define PT_A1 24
#define PT_A2 28
#define PT_PC 46
#define PT_SR 44
#define PT_VECTOR 50
#define IRQ_HANDLER 0
......@@ -35,6 +45,10 @@
#define FBCON_FONT_DESC_HEIGHT 12
#define FBCON_FONT_DESC_DATA 16
#define FBCON_FONT_DESC_PREF 20
#define SIGSEGV 11
#define SEGV_MAPERR 1
#define SIGTRAP 5
#define TRAP_TRACE 2
#define CUSTOMBASE -2132807680
#define C_INTENAR 28
#define C_INTREQR 30
......
......@@ -58,7 +58,7 @@ static void default_idle(void)
{
while(1) {
if (!current->need_resched)
#ifdef MACH_ATARI_ONLY
#if defined(MACH_ATARI_ONLY) && !defined(CONFIG_HADES)
/* block out HSYNC on the atari (falcon) */
__asm__("stop #0x2200" : : : "cc");
#else
......@@ -161,9 +161,10 @@ void flush_thread(void)
unsigned long zero = 0;
set_fs(USER_DS);
current->thread.fs = __USER_DS;
asm volatile (".chip 68k/68881\n\t"
"frestore %0@\n\t"
".chip 68k" : : "a" (&zero));
if (!FPU_IS_EMU)
asm volatile (".chip 68k/68881\n\t"
"frestore %0@\n\t"
".chip 68k" : : "a" (&zero));
}
/*
......@@ -224,16 +225,18 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
*/
p->thread.fs = get_fs().seg;
/* Copy the current fpu state */
asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2])
asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
"fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
: : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0])
: "memory");
/* Restore the state in case the fpu was busy */
asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
if (!FPU_IS_EMU) {
/* Copy the current fpu state */
asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2])
asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
"fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
: : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0])
: "memory");
/* Restore the state in case the fpu was busy */
asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
}
return 0;
}
......@@ -244,18 +247,32 @@ int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu)
{
char fpustate[216];
/* First dump the fpu context to avoid protocol violation. */
asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2])
return 0;
if (FPU_IS_EMU) {
int i;
memcpy(fpu->fpcntl, current->thread.fpcntl, 12);
memcpy(fpu->fpregs, current->thread.fp, 96);
/* Convert internal fpu reg representation
* into long double format
*/
for (i = 0; i < 24; i += 3)
fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) |
((fpu->fpregs[i] & 0x0000ffff) << 16);
return 1;
}
/* First dump the fpu context to avoid protocol violation. */
asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2])
return 0;
asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
:: "m" (fpu->fpcntl[0])
: "memory");
asm volatile ("fmovemx %/fp0-%/fp7,%0"
asm volatile ("fmovemx %/fp0-%/fp7,%0"
:: "m" (fpu->fpregs[0])
: "memory");
return 1;
return 1;
}
/*
......
......@@ -18,6 +18,7 @@
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/user.h>
#include <linux/config.h>
#include <asm/uaccess.h>
#include <asm/page.h>
......@@ -384,10 +385,17 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
tmp = get_reg(child, addr);
if (addr == PT_SR)
tmp >>= 16;
}
else if (addr >= 21 && addr < 49)
} else if (addr >= 21 && addr < 49) {
tmp = child->thread.fp[addr - 21];
else
#ifdef CONFIG_M68KFPU_EMU
/* Convert internal fpu reg representation
* into long double format
*/
if (FPU_IS_EMU && (addr < 45) && !(addr % 3))
tmp = ((tmp & 0xffff0000) << 15) |
((tmp & 0x0000ffff) << 16);
#endif
} else
goto out;
ret = put_user(tmp,(unsigned long *) data);
goto out;
......@@ -423,6 +431,16 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
}
if (addr >= 21 && addr < 48)
{
#ifdef CONFIG_M68KFPU_EMU
/* Convert long double format
* into internal fpu reg representation
*/
if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) {
data = (unsigned long)data << 15;
data = (data & 0xffff0000) |
((data & 0x0000ffff) >> 1);
}
#endif
child->thread.fp[addr - 21] = data;
ret = 0;
}
......
......@@ -14,6 +14,10 @@
* 68060 fixes by Jesper Skov
*
* 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab
*
* mathemu support by Roman Zippel
* (Note: fpstate in the signal context is completly ignored for the emulator
* and the internal floating point format is put on stack)
*/
/*
......@@ -190,6 +194,13 @@ static inline int restore_fpu_state(struct sigcontext *sc)
{
int err = 1;
if (FPU_IS_EMU) {
/* restore registers */
memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12);
memcpy(current->thread.fp, sc->sc_fpregs, 24);
return 0;
}
if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
/* Verify the frame format. */
if (!CPU_IS_060 && (sc->sc_fpstate[0] != fpu_version))
......@@ -242,6 +253,18 @@ static inline int rt_restore_fpu_state(struct ucontext *uc)
fpregset_t fpregs;
int err = 1;
if (FPU_IS_EMU) {
/* restore fpu control register */
if (__copy_from_user(current->thread.fpcntl,
&uc->uc_mcontext.fpregs.f_pcr, 12))
goto out;
/* restore all other fpu register */
if (__copy_from_user(current->thread.fp,
uc->uc_mcontext.fpregs.f_fpregs, 96))
goto out;
return 0;
}
if (__get_user(*(long *)fpstate, (long *)&uc->uc_fpstate))
goto out;
if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
......@@ -539,6 +562,13 @@ asmlinkage int do_rt_sigreturn(unsigned long __unused)
static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs)
{
if (FPU_IS_EMU) {
/* save registers */
memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12);
memcpy(sc->sc_fpregs, current->thread.fp, 24);
return;
}
__asm__ volatile (".chip 68k/68881\n\t"
"fsave %0\n\t"
".chip 68k"
......@@ -570,6 +600,16 @@ static inline int rt_save_fpu_state(struct ucontext *uc, struct pt_regs *regs)
int context_size = CPU_IS_060 ? 8 : 0;
int err = 0;
if (FPU_IS_EMU) {
/* save fpu control register */
err |= copy_to_user(&uc->uc_mcontext.fpregs.f_pcr,
current->thread.fpcntl, 12);
/* save all other fpu register */
err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs,
current->thread.fp, 96);
return err;
}
__asm__ volatile (".chip 68k/68881\n\t"
"fsave %0\n\t"
".chip 68k"
......
......@@ -47,6 +47,7 @@ asmlinkage void buserr(void);
asmlinkage void trap(void);
asmlinkage void inthandler(void);
asmlinkage void nmihandler(void);
asmlinkage void fpu_emu(void);
e_vector vectors[256] = {
0, 0, buserr, trap, trap, trap, trap, trap,
......@@ -65,12 +66,12 @@ asm(".text\n"
__ALIGN_STR "\n"
SYMBOL_NAME_STR(nmihandler) ": rte");
__initfunc(void base_trap_init(void))
void __init base_trap_init(void)
{
/* setup the exception vector table */
__asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors));
if (CPU_IS_040) {
if (CPU_IS_040 && !FPU_IS_EMU) {
/* set up FPSP entry points */
asmlinkage void dz_vec(void) asm ("dz");
asmlinkage void inex_vec(void) asm ("inex");
......@@ -93,6 +94,12 @@ __initfunc(void base_trap_init(void))
vectors[VEC_FPUNSUP] = unsupp_vec;
}
if (CPU_IS_060) {
/* set up ISP entry points */
asmlinkage void unimp_vec(void) asm ("_060_isp_unimp");
vectors[VEC_UNIMPII] = unimp_vec;
}
if (CPU_IS_060 && !FPU_IS_EMU) {
/* set up IFPSP entry points */
asmlinkage void snan_vec(void) asm ("_060_fpsp_snan");
asmlinkage void operr_vec(void) asm ("_060_fpsp_operr");
......@@ -104,8 +111,6 @@ __initfunc(void base_trap_init(void))
asmlinkage void unsupp_vec(void) asm ("_060_fpsp_unsupp");
asmlinkage void effadd_vec(void) asm ("_060_fpsp_effadd");
asmlinkage void unimp_vec(void) asm ("_060_isp_unimp");
vectors[VEC_FPNAN] = snan_vec;
vectors[VEC_FPOE] = operr_vec;
vectors[VEC_FPOVER] = ovfl_vec;
......@@ -115,14 +120,10 @@ __initfunc(void base_trap_init(void))
vectors[VEC_LINE11] = fline_vec;
vectors[VEC_FPUNSUP] = unsupp_vec;
vectors[VEC_UNIMPEA] = effadd_vec;
/* set up ISP entry points */
vectors[VEC_UNIMPII] = unimp_vec;
}
}
__initfunc(void trap_init (void))
void __init trap_init (void)
{
int i;
......@@ -133,18 +134,17 @@ __initfunc(void trap_init (void))
for (i = 64; i < 256; i++)
vectors[i] = inthandler;
#ifdef CONFIG_M68KFPU_EMU
if (FPU_IS_EMU)
vectors[VEC_LINE11] = fpu_emu;
#endif
/* if running on an amiga, make the NMI interrupt do nothing */
if (MACH_IS_AMIGA) {
vectors[VEC_INT7] = nmihandler;
}
}
void set_evector(int vecnum, void (*handler)(void))
{
if (vecnum >= 0 && vecnum <= 256)
vectors[vecnum] = handler;
}
static inline void console_verbose(void)
{
......@@ -152,6 +152,7 @@ static inline void console_verbose(void)
console_loglevel = 15;
}
static char *vec_names[] = {
"RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR",
"ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc",
......@@ -180,7 +181,6 @@ static char *space_names[] = {
};
void die_if_kernel(char *,struct pt_regs *,int);
asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
unsigned long error_code);
......@@ -507,44 +507,6 @@ static inline void bus_error030 (struct frame *fp)
else
asm volatile ("ploadr %1,%0@" : /* no outputs */
: "a" (addr), "d" (ssw));
#if 0
/* If this was a data fault due to an invalid page and a
prefetch is pending on the same page, simulate it (but
only if the page is now valid). Otherwise we'll get an
weird insn access. */
if ((ssw & RB) && (mmusr & MMU_I))
{
unsigned long iaddr;
if ((fp->ptregs.format) == 0xB)
iaddr = fp->un.fmtb.baddr;
else
iaddr = fp->ptregs.pc + 4;
if (((addr ^ iaddr) & PAGE_MASK) == 0)
{
/* We only need to check the ATC as the entry has
already been set up above. */
asm volatile ("ptestr #1,%1@,#0\n\t"
"pmove %/psr,%0@"
: : "a" (&temp), "a" (iaddr));
mmusr = temp;
#ifdef DEBUG
printk ("prefetch iaddr=%#lx ssw=%#x mmusr=%#x\n",
iaddr, ssw, mmusr);
#endif
if (!(mmusr & MMU_I))
{
unsigned short insn;
asm volatile ("movesw %1@,%0"
: "=r" (insn)
: "a" (iaddr));
fp->un.fmtb.isb = insn;
fp->un.fmtb.ssw &= ~RB;
}
}
}
#endif
}
/* Now handle the instruction fault. */
......@@ -598,43 +560,6 @@ static inline void bus_error030 (struct frame *fp)
die_if_kernel("Oops",&fp->ptregs,mmusr);
force_sig(SIGSEGV, current);
return;
} else {
#if 0 /* stale ATC entry?? Ignore it */
#ifdef DEBUG
static volatile long tlong;
#endif
printk ("weird insn access at %#lx from pc %#lx (ssw is %#x)\n",
addr, fp->ptregs.pc, ssw);
asm volatile ("ptestr #1,%1@,#0\n\t"
"pmove %/psr,%0@"
: /* no outputs */
: "a" (&temp), "a" (addr));
mmusr = temp;
printk ("level 0 mmusr is %#x\n", mmusr);
#ifdef DEBUG
if (m68k_cputype & CPU_68030) {
asm volatile ("pmove %/tt0,%0@"
: /* no outputs */
: "a" (&tlong));
printk ("tt0 is %#lx, ", tlong);
asm volatile ("pmove %/tt1,%0@"
: /* no outputs */
: "a" (&tlong));
printk ("tt1 is %#lx\n", tlong);
}
#endif
#if DEBUG
printk("Unknown SIGSEGV - 3\n");
#endif
die_if_kernel("Oops",&fp->ptregs,mmusr);
force_sig(SIGSEGV, current);
return;
#endif
}
create_atc_entry:
......@@ -990,3 +915,16 @@ asmlinkage void fpsp040_die(void)
{
do_exit(SIGSEGV);
}
#ifdef CONFIG_M68KFPU_EMU
asmlinkage void fpemu_signal(int signal, int code, void *addr)
{
siginfo_t info;
info.si_signo = signal;
info.si_errno = 0;
info.si_code = code;
info.si_addr = addr;
force_sig_info(signal, &info, current);
}
#endif
#
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
# Note 2! The CFLAGS definitions are now in the main makefile...
.S.o:
$(CC) $(EXTRA_CFLAGS) -D__ASSEMBLY__ -traditional -c $< -o $*.o
#EXTRA_CFLAGS=-DFPU_EMU_DEBUG
O_TARGET := mathemu.o
O_OBJS := fp_entry.o fp_scan.o fp_util.o fp_move.o fp_movem.o \
fp_cond.o fp_arith.o fp_log.o fp_trig.o
include $(TOPDIR)/Rules.make
This diff is collapsed.
/*
fp_arith.h: floating-point math routines for the Linux-m68k
floating point emulator.
Copyright (c) 1998 David Huggins-Daines.
Somewhat based on the AlphaLinux floating point emulator, by David
Mosberger-Tang.
You may copy, modify, and redistribute this file under the terms of
the GNU General Public License, version 2, or any later version, at
your convenience.
*/
#ifndef FP_ARITH_H
#define FP_ARITH_H
/* easy ones */
struct fp_ext *
fp_fabs(struct fp_ext *dest, struct fp_ext *src);
struct fp_ext *
fp_fneg(struct fp_ext *dest, struct fp_ext *src);
/* straightforward arithmetic */
struct fp_ext *
fp_fadd(struct fp_ext *dest, struct fp_ext *src);
struct fp_ext *
fp_fsub(struct fp_ext *dest, struct fp_ext *src);
struct fp_ext *
fp_fcmp(struct fp_ext *dest, struct fp_ext *src);
struct fp_ext *
fp_ftst(struct fp_ext *dest, struct fp_ext *src);
struct fp_ext *
fp_fmul(struct fp_ext *dest, struct fp_ext *src);
struct fp_ext *
fp_fdiv(struct fp_ext *dest, struct fp_ext *src);
/* ones that do rounding and integer conversions */
struct fp_ext *
fp_fmod(struct fp_ext *dest, struct fp_ext *src);
struct fp_ext *
fp_frem(struct fp_ext *dest, struct fp_ext *src);
struct fp_ext *
fp_fint(struct fp_ext *dest, struct fp_ext *src);
struct fp_ext *
fp_fintrz(struct fp_ext *dest, struct fp_ext *src);
struct fp_ext *
fp_fscale(struct fp_ext *dest, struct fp_ext *src);
#endif /* FP_ARITH__H */
/*
* fp_cond.S
*
* Copyright Roman Zippel, 1997. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, and the entire permission notice in its entirety,
* including the disclaimer of warranties.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* ALTERNATIVELY, this product may be distributed under the terms of
* the GNU Public License, in which case the provisions of the GPL are
* required INSTEAD OF the above restrictions. (This clause is
* necessary due to a potential bad interaction between the GPL and
* the restrictions contained in a BSD-style copyright.)
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fp_emu.h"
#include "fp_decode.h"
.globl fp_fscc, fp_fbccw, fp_fbccl
#ifdef FPU_EMU_DEBUG
fp_fnop:
printf PDECODE,"fnop\n"
jra fp_end
#else
#define fp_fnop fp_end
#endif
fp_fbccw:
tst.w %d2
jeq fp_fnop
printf PDECODE,"fbccw "
fp_get_pc %a0
lea (-2,%a0,%d2.w),%a0
jra 1f
fp_fbccl:
printf PDECODE,"fbccl "
fp_get_pc %a0
move.l %d2,%d0
swap %d0
fp_get_instr_word %d0,fp_err_ua1
lea (-2,%a0,%d0.l),%a0
1: printf PDECODE,"%x",1,%a0
move.l %d2,%d0
swap %d0
jsr fp_compute_cond
tst.l %d0
jeq 1f
fp_put_pc %a0,1
1: printf PDECODE,"\n"
jra fp_end
fp_fdbcc:
printf PDECODE,"fdbcc "
fp_get_pc %a1 | calculate new pc
fp_get_instr_word %d0,fp_err_ua1
add.w %d0,%a1
fp_decode_addr_reg
printf PDECODE,"d%d,%x\n",2,%d0,%a1
swap %d1 | test condition in %d1
tst.w %d1
jne 2f
move.l %d0,%d1
jsr fp_get_data_reg
subq.w #1,%d0
jcs 1f
fp_put_pc %a1,1
1: jsr fp_put_data_reg
2: jra fp_end
| set flags for decode macros for fs<cc>
do_fscc=1
do_no_pc_mode=1
fp_fscc:
printf PDECODE,"fscc "
move.l %d2,%d0
jsr fp_compute_cond
move.w %d0,%d1
swap %d1
| decode addressing mode
fp_decode_addr_mode
.long fp_data, fp_fdbcc
.long fp_indirect, fp_postinc
.long fp_predecr, fp_disp16
.long fp_extmode0, fp_extmode1
| addressing mode: data register direct
fp_data:
fp_mode_data_direct
move.w %d0,%d1 | save register nr
jsr fp_get_data_reg
swap %d1
move.b %d1,%d0
swap %d1
jsr fp_put_data_reg
printf PDECODE,"\n"
jra fp_end
fp_indirect:
fp_mode_addr_indirect
jra fp_do_scc
fp_postinc:
fp_mode_addr_indirect_postinc
jra fp_do_scc
fp_predecr:
fp_mode_addr_indirect_predec
jra fp_do_scc
fp_disp16:
fp_mode_addr_indirect_disp16
jra fp_do_scc
fp_extmode0:
fp_mode_addr_indirect_extmode0
jra fp_do_scc
fp_extmode1:
bfextu %d2{#13,#3},%d0
jmp ([0f:w,%pc,%d0*4])
.align 4
0:
.long fp_absolute_short, fp_absolute_long
.long fp_ill, fp_ill | NOTE: jump here to ftrap.x
.long fp_ill, fp_ill
.long fp_ill, fp_ill
fp_absolute_short:
fp_mode_abs_short
jra fp_do_scc
fp_absolute_long:
fp_mode_abs_long
| jra fp_do_scc
fp_do_scc:
swap %d1
putuser.b %d1,(%a0),fp_err_ua1,%a0
printf PDECODE,"\n"
jra fp_end
#define tst_NAN btst #24,%d1
#define tst_Z btst #26,%d1
#define tst_N btst #27,%d1
fp_compute_cond:
move.l (FPD_FPSR,FPDATA),%d1
btst #4,%d0
jeq 1f
tst_NAN
jeq 1f
bset #15,%d1
bset #7,%d1
move.l %d1,(FPD_FPSR,FPDATA)
1: and.w #0xf,%d0
jmp ([0f:w,%pc,%d0.w*4])
.align 4
0:
.long fp_f , fp_eq , fp_ogt, fp_oge
.long fp_olt, fp_ole, fp_ogl, fp_or
.long fp_un , fp_ueq, fp_ugt, fp_uge
.long fp_ult, fp_ule, fp_ne , fp_t
fp_f:
moveq #0,%d0
rts
fp_eq:
moveq #0,%d0
tst_Z
jeq 1f
moveq #-1,%d0
1: rts
fp_ogt:
moveq #0,%d0
tst_NAN
jne 1f
tst_Z
jne 1f
tst_N
jne 1f
moveq #-1,%d0
1: rts
fp_oge:
moveq #-1,%d0
tst_Z
jne 2f
tst_NAN
jne 1f
tst_N
jeq 2f
1: moveq #0,%d0
2: rts
fp_olt:
moveq #0,%d0
tst_NAN
jne 1f
tst_Z
jne 1f
tst_N
jeq 1f
moveq #-1,%d0
1: rts
fp_ole:
moveq #-1,%d0
tst_Z
jne 2f
tst_NAN
jne 1f
tst_N
jne 2f
1: moveq #0,%d0
2: rts
fp_ogl:
moveq #0,%d0
tst_NAN
jne 1f
tst_Z
jne 1f
moveq #-1,%d0
1: rts
fp_or:
moveq #0,%d0
tst_NAN
jne 1f
moveq #-1,%d0
1: rts
fp_un:
moveq #0,%d0
tst_NAN
jeq 1f
moveq #-1,%d0
rts
fp_ueq:
moveq #-1,%d0
tst_NAN
jne 1f
tst_Z
jne 1f
moveq #0,%d0
1: rts
fp_ugt:
moveq #-1,%d0
tst_NAN
jne 2f
tst_N
jne 1f
tst_Z
jeq 2f
1: moveq #0,%d0
2: rts
fp_uge:
moveq #-1,%d0
tst_NAN
jne 1f
tst_Z
jne 1f
tst_N
jeq 1f
moveq #0,%d0
1: rts
fp_ult:
moveq #-1,%d0
tst_NAN
jne 2f
tst_Z
jne 1f
tst_N
jne 2f
1: moveq #0,%d0
2: rts
fp_ule:
moveq #-1,%d0
tst_NAN
jne 1f
tst_Z
jne 1f
tst_N
jne 1f
moveq #0,%d0
1: rts
fp_ne:
moveq #0,%d0
tst_Z
jne 1f
moveq #-1,%d0
1: rts
fp_t:
moveq #-1,%d0
rts
This diff is collapsed.
/*
* fp_emu.h
*
* Copyright Roman Zippel, 1997. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, and the entire permission notice in its entirety,
* including the disclaimer of warranties.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* ALTERNATIVELY, this product may be distributed under the terms of
* the GNU Public License, in which case the provisions of the GPL are
* required INSTEAD OF the above restrictions. (This clause is
* necessary due to a potential bad interaction between the GPL and
* the restrictions contained in a BSD-style copyright.)
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FP_EMU_H
#define _FP_EMU_H
#ifndef __ASSEMBLY__
#include <asm/math-emu.h>
#define IS_INF(a) ((a)->exp == 0x7fff)
#define IS_ZERO(a) ((a)->mant.m64 == 0)
#define fp_set_sr(bit) ({ \
FPDATA->fpsr |= 1 << (bit); \
})
#define fp_set_quotient(quotient) ({ \
FPDATA->fpsr &= 0xff00ffff; \
FPDATA->fpsr |= ((quotient) & 0xff) << 16; \
})
/* linkage for several useful functions */
/* Normalize the extended struct, return 0 for a NaN */
#define fp_normalize_ext(fpreg) ({ \
register struct fp_ext *reg asm ("a0") = fpreg; \
register int res asm ("d0"); \
\
asm volatile ("jsr fp_conv_ext2ext" \
: "=d" (res) : "a" (reg) \
: "a1", "d1", "d2", "memory"); \
res; \
})
#define fp_copy_ext(dest, src) ({ \
*dest = *src; \
})
#define fp_monadic_check(dest, src) ({ \
fp_copy_ext(dest, src); \
if (!fp_normalize_ext(dest)) \
return dest; \
})
#define fp_dyadic_check(dest, src) ({ \
if (!fp_normalize_ext(dest)) \
return dest; \
if (!fp_normalize_ext(src)) { \
fp_copy_ext(dest, src); \
return dest; \
} \
})
extern const struct fp_ext fp_QNaN;
extern const struct fp_ext fp_Inf;
#define fp_set_nan(dest) ({ \
fp_set_sr(FPSR_EXC_OPERR); \
*dest = fp_QNaN; \
})
/* TODO check rounding mode? */
#define fp_set_ovrflw(dest) ({ \
fp_set_sr(FPSR_EXC_OVFL); \
dest->exp = 0x7fff; \
dest->mant.m64 = 0; \
})
#define fp_conv_ext2long(src) ({ \
register struct fp_ext *__src asm ("a0") = src; \
register int __res asm ("d0"); \
\
asm volatile ("jsr fp_conv_ext2long" \
: "=d" (__res) : "a" (__src) \
: "a1", "d1", "d2", "memory"); \
__res; \
})
#else /* __ASSEMBLY__ */
#include "../kernel/m68k_defs.h"
#include <asm/math-emu.h>
/*
* set, reset or clear a bit in the fp status register
*/
.macro fp_set_sr bit
bset #(\bit&7),(FPD_FPSR+3-(\bit/8),FPDATA)
.endm
.macro fp_clr_sr bit
bclr #(\bit&7),(FPD_FPSR+3-(\bit/8),FPDATA)
.endm
.macro fp_tst_sr bit
btst #(\bit&7),(FPD_FPSR+3-(\bit/8),FPDATA)
.endm
#endif /* __ASSEMBLY__ */
#endif /* _FP_EMU_H */
/*
* fp_emu.S
*
* Copyright Roman Zippel, 1997. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, and the entire permission notice in its entirety,
* including the disclaimer of warranties.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* ALTERNATIVELY, this product may be distributed under the terms of
* the GNU Public License, in which case the provisions of the GPL are
* required INSTEAD OF the above restrictions. (This clause is
* necessary due to a potential bad interaction between the GPL and
* the restrictions contained in a BSD-style copyright.)
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <linux/config.h>
#include <linux/linkage.h>
#include <asm/entry.h>
#include "fp_emu.h"
.globl SYMBOL_NAME(fpu_emu)
.globl fp_debugprint
.globl fp_err_ua1,fp_err_ua2
.text
SYMBOL_NAME_LABEL(fpu_emu)
SAVE_ALL_INT
GET_CURRENT(%d0)
#if defined(CPU_M68020_OR_M68030) && defined(CPU_M68040_OR_M68060)
tst.l SYMBOL_NAME(m68k_is040or060)
jeq 1f
#endif
#if defined(CPU_M68040_OR_M68060)
move.l (FPS_PC2,%sp),(FPS_PC,%sp)
#endif
1:
| emulate the instruction
jsr fp_scan
#if defined(CONFIG_M68060)
#if !defined(CPU_M68060_ONLY)
btst #3,SYMBOL_NAME(m68k_cputype)+3
jeq 1f
#endif
btst #7,(FPS_SR,%sp)
jne fp_sendtrace060
#endif
1:
| emulation successful?
tst.l %d0
jeq SYMBOL_NAME(ret_from_exception)
| send some signal to program here
jra SYMBOL_NAME(ret_from_exception)
| we jump here after an access error while trying to access
| user space, we correct stackpointer and send a SIGSEGV to
| the user process
fp_err_ua2:
addq.l #4,%sp
fp_err_ua1:
addq.l #4,%sp
move.l %a0,-(%sp)
pea SEGV_MAPERR
pea SIGSEGV
jsr SYMBOL_NAME(fpemu_signal)
add.w #12,%sp
jra SYMBOL_NAME(ret_from_exception)
#if defined(CONFIG_M68060)
| send a trace signal if we are debugged
| it does not really belong here, but...
fp_sendtrace060:
move.l (FPS_PC,%sp),-(%sp)
pea TRAP_TRACE
pea SIGTRAP
jsr SYMBOL_NAME(fpemu_signal)
add.w #12,%sp
jra SYMBOL_NAME(ret_from_exception)
#endif
.globl fp_get_data_reg, fp_put_data_reg
.globl fp_get_addr_reg, fp_put_addr_reg
| Entry points to get/put a register. Some of them can be get/put
| directly, others are on the stack, as we read/write the stack
| directly here, these function may only be called from within
| instruction decoding, otherwise the stack pointer is incorrect
| and the stack gets corrupted.
fp_get_data_reg:
jmp ([0f:w,%pc,%d0.w*4])
.align 4
0:
.long fp_get_d0, fp_get_d1
.long fp_get_d2, fp_get_d3
.long fp_get_d4, fp_get_d5
.long fp_get_d6, fp_get_d7
fp_get_d0:
move.l (PT_D0+8,%sp),%d0
printf PREGISTER,"{d0->%08x}",1,%d0
rts
fp_get_d1:
move.l (PT_D1+8,%sp),%d0
printf PREGISTER,"{d1->%08x}",1,%d0
rts
fp_get_d2:
move.l (PT_D2+8,%sp),%d0
printf PREGISTER,"{d2->%08x}",1,%d0
rts
fp_get_d3:
move.l %d3,%d0
printf PREGISTER,"{d3->%08x}",1,%d0
rts
fp_get_d4:
move.l %d4,%d0
printf PREGISTER,"{d4->%08x}",1,%d0
rts
fp_get_d5:
move.l %d5,%d0
printf PREGISTER,"{d5->%08x}",1,%d0
rts
fp_get_d6:
move.l %d6,%d0
printf PREGISTER,"{d6->%08x}",1,%d0
rts
fp_get_d7:
move.l %d7,%d0
printf PREGISTER,"{d7->%08x}",1,%d0
rts
fp_put_data_reg:
jmp ([0f:w,%pc,%d1.w*4])
.align 4
0:
.long fp_put_d0, fp_put_d1
.long fp_put_d2, fp_put_d3
.long fp_put_d4, fp_put_d5
.long fp_put_d6, fp_put_d7
fp_put_d0:
printf PREGISTER,"{d0<-%08x}",1,%d0
move.l %d0,(PT_D0+8,%sp)
rts
fp_put_d1:
printf PREGISTER,"{d1<-%08x}",1,%d0
move.l %d0,(PT_D1+8,%sp)
rts
fp_put_d2:
printf PREGISTER,"{d2<-%08x}",1,%d0
move.l %d0,(PT_D2+8,%sp)
rts
fp_put_d3:
printf PREGISTER,"{d3<-%08x}",1,%d0
| move.l %d0,%d3
move.l %d0,(PT_D3+8,%sp)
rts
fp_put_d4:
printf PREGISTER,"{d4<-%08x}",1,%d0
| move.l %d0,%d4
move.l %d0,(PT_D4+8,%sp)
rts
fp_put_d5:
printf PREGISTER,"{d5<-%08x}",1,%d0
| move.l %d0,%d5
move.l %d0,(PT_D5+8,%sp)
rts
fp_put_d6:
printf PREGISTER,"{d6<-%08x}",1,%d0
move.l %d0,%d6
rts
fp_put_d7:
printf PREGISTER,"{d7<-%08x}",1,%d0
move.l %d0,%d7
rts
fp_get_addr_reg:
jmp ([0f:w,%pc,%d0.w*4])
.align 4
0:
.long fp_get_a0, fp_get_a1
.long fp_get_a2, fp_get_a3
.long fp_get_a4, fp_get_a5
.long fp_get_a6, fp_get_a7
fp_get_a0:
move.l (PT_A0+8,%sp),%a0
printf PREGISTER,"{a0->%08x}",1,%a0
rts
fp_get_a1:
move.l (PT_A1+8,%sp),%a0
printf PREGISTER,"{a1->%08x}",1,%a0
rts
fp_get_a2:
move.l (PT_A2+8,%sp),%a0
printf PREGISTER,"{a2->%08x}",1,%a0
rts
fp_get_a3:
move.l %a3,%a0
printf PREGISTER,"{a3->%08x}",1,%a0
rts
fp_get_a4:
move.l %a4,%a0
printf PREGISTER,"{a4->%08x}",1,%a0
rts
fp_get_a5:
move.l %a5,%a0
printf PREGISTER,"{a5->%08x}",1,%a0
rts
fp_get_a6:
move.l %a6,%a0
printf PREGISTER,"{a6->%08x}",1,%a0
rts
fp_get_a7:
move.l %usp,%a0
printf PREGISTER,"{a7->%08x}",1,%a0
rts
fp_put_addr_reg:
jmp ([0f:w,%pc,%d0.w*4])
.align 4
0:
.long fp_put_a0, fp_put_a1
.long fp_put_a2, fp_put_a3
.long fp_put_a4, fp_put_a5
.long fp_put_a6, fp_put_a7
fp_put_a0:
printf PREGISTER,"{a0<-%08x}",1,%a0
move.l %a0,(PT_A0+8,%sp)
rts
fp_put_a1:
printf PREGISTER,"{a1<-%08x}",1,%a0
move.l %a0,(PT_A1+8,%sp)
rts
fp_put_a2:
printf PREGISTER,"{a2<-%08x}",1,%a0
move.l %a0,(PT_A2+8,%sp)
rts
fp_put_a3:
printf PREGISTER,"{a3<-%08x}",1,%a0
move.l %a0,%a3
rts
fp_put_a4:
printf PREGISTER,"{a4<-%08x}",1,%a0
move.l %a0,%a4
rts
fp_put_a5:
printf PREGISTER,"{a5<-%08x}",1,%a0
move.l %a0,%a5
rts
fp_put_a6:
printf PREGISTER,"{a6<-%08x}",1,%a0
move.l %a0,%a6
rts
fp_put_a7:
printf PREGISTER,"{a7<-%08x}",1,%a0
move.l %a0,%usp
rts
.data
.align 4
fp_debugprint:
| .long PMDECODE
.long PMINSTR+PMDECODE+PMCONV+PMNORM
| .long PMCONV+PMNORM+PMINSTR
| .long 0
/*
fp_trig.c: floating-point math routines for the Linux-m68k
floating point emulator.
Copyright (c) 1998-1999 David Huggins-Daines / Roman Zippel.
I hereby give permission, free of charge, to copy, modify, and
redistribute this software, in source or binary form, provided that
the above copyright notice and the following disclaimer are included
in all such copies.
THIS SOFTWARE IS PROVIDED "AS IS", WITH ABSOLUTELY NO WARRANTY, REAL
OR IMPLIED.
*/
#include "fp_emu.h"
struct fp_ext *
fp_fsqrt(struct fp_ext *dest, struct fp_ext *src)
{
uprint("fsqrt\n");
fp_monadic_check(dest, src);
if (IS_ZERO(dest))
return dest;
if (dest->sign) {
fp_set_nan(dest);
return dest;
}
if (IS_INF(dest))
return dest;
return dest;
}
struct fp_ext *
fp_fetoxm1(struct fp_ext *dest, struct fp_ext *src)
{
uprint("fetoxm1\n");
fp_monadic_check(dest, src);
if (IS_ZERO(dest))
return dest;
return dest;
}
struct fp_ext *
fp_fetox(struct fp_ext *dest, struct fp_ext *src)
{
uprint("fetox\n");
fp_monadic_check(dest, src);
return dest;
}
struct fp_ext *
fp_ftwotox(struct fp_ext *dest, struct fp_ext *src)
{
uprint("ftwotox\n");
fp_monadic_check(dest, src);
return dest;
}
struct fp_ext *
fp_ftentox(struct fp_ext *dest, struct fp_ext *src)
{
uprint("ftentox\n");
fp_monadic_check(dest, src);
return dest;
}
struct fp_ext *
fp_flogn(struct fp_ext *dest, struct fp_ext *src)
{
uprint("flogn\n");
fp_monadic_check(dest, src);
return dest;
}
struct fp_ext *
fp_flognp1(struct fp_ext *dest, struct fp_ext *src)
{
uprint("flognp1\n");
fp_monadic_check(dest, src);
return dest;
}
struct fp_ext *
fp_flog10(struct fp_ext *dest, struct fp_ext *src)
{
uprint("flog10\n");
fp_monadic_check(dest, src);
return dest;
}
struct fp_ext *
fp_flog2(struct fp_ext *dest, struct fp_ext *src)
{
uprint("flog2\n");
fp_monadic_check(dest, src);
return dest;
}
struct fp_ext *
fp_fgetexp(struct fp_ext *dest, struct fp_ext *src)
{
uprint("fgetexp\n");
fp_monadic_check(dest, src);
return dest;
}
struct fp_ext *
fp_fgetman(struct fp_ext *dest, struct fp_ext *src)
{
uprint("fgetman\n");
fp_monadic_check(dest, src);
return dest;
}
/*
* fp_move.S
*
* Copyright Roman Zippel, 1997. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, and the entire permission notice in its entirety,
* including the disclaimer of warranties.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* ALTERNATIVELY, this product may be distributed under the terms of
* the GNU Public License, in which case the provisions of the GPL are
* required INSTEAD OF the above restrictions. (This clause is
* necessary due to a potential bad interaction between the GPL and
* the restrictions contained in a BSD-style copyright.)
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fp_emu.h"
#include "fp_decode.h"
do_no_pc_mode=1
.globl fp_fmove_fp2mem
fp_fmove_fp2mem:
clr.b (2+FPD_FPSR,FPDATA)
fp_decode_dest_format
move.w %d0,%d1 | store data size twice in %d1
swap %d1 | one can be trashed below
move.w %d0,%d1
#ifdef FPU_EMU_DEBUG
lea 0f,%a0
clr.l %d0
move.b (%a0,%d1.w),%d0
printf PDECODE,"fmove.%c ",1,%d0
fp_decode_src_reg
printf PDECODE,"fp%d,",1,%d0
.data
0: .byte 'l','s','x','p','w','d','b','p'
.previous
#endif
| encode addressing mode for dest
fp_decode_addr_mode
.long fp_data, fp_ill
.long fp_indirect, fp_postinc
.long fp_predecr, fp_disp16
.long fp_extmode0, fp_extmode1
| addressing mode: data register direct
fp_data:
fp_mode_data_direct
move.w %d0,%d1
fp_decode_src_reg
fp_get_fp_reg
lea (FPD_TEMPFP1,FPDATA),%a1
move.l (%a0)+,(%a1)+
move.l (%a0)+,(%a1)+
move.l (%a0),(%a1)
lea (-8,%a1),%a0
swap %d1
move.l %d1,%d2
printf PDECODE,"\n"
jmp ([0f:w,%pc,%d1.w*4])
.align 4
0:
.long fp_data_long, fp_data_single
.long fp_ill, fp_ill
.long fp_data_word, fp_ill
.long fp_data_byte, fp_ill
fp_data_byte:
jsr fp_normalize_ext
jsr fp_conv_ext2byte
move.l %d0,%d1
swap %d2
move.w %d2,%d0
jsr fp_get_data_reg
move.b %d1,%d0
move.w %d2,%d1
jsr fp_put_data_reg
jra fp_final
fp_data_word:
jsr fp_normalize_ext
jsr fp_conv_ext2short
move.l %d0,%d1
swap %d2
move.w %d2,%d0
jsr fp_get_data_reg
move.w %d1,%d0
move.l %d2,%d1
jsr fp_put_data_reg
jra fp_final
fp_data_long:
jsr fp_normalize_ext
jsr fp_conv_ext2long
swap %d2
move.w %d2,%d1
jsr fp_put_data_reg
jra fp_final
fp_data_single:
jsr fp_normalize_ext
jsr fp_conv_ext2single
swap %d2
move.w %d2,%d1
jsr fp_put_data_reg
jra fp_final
| addressing mode: address register indirect
fp_indirect:
fp_mode_addr_indirect
jra fp_putdest
| addressing mode: address register indirect with postincrement
fp_postinc:
fp_mode_addr_indirect_postinc
jra fp_putdest
| addressing mode: address register indirect with predecrement
fp_predecr:
fp_mode_addr_indirect_predec
jra fp_putdest
| addressing mode: address register indirect with 16bit displacement
fp_disp16:
fp_mode_addr_indirect_disp16
jra fp_putdest
fp_extmode0:
fp_mode_addr_indirect_extmode0
jra fp_putdest
fp_extmode1:
fp_decode_addr_reg
jmp ([0f:w,%pc,%d0*4])
.align 4
0:
.long fp_abs_short, fp_abs_long
.long fp_ill, fp_ill
.long fp_ill, fp_ill
.long fp_ill, fp_ill
fp_abs_short:
fp_mode_abs_short
jra fp_putdest
fp_abs_long:
fp_mode_abs_long
jra fp_putdest
fp_putdest:
move.l %a0,%a1
fp_decode_src_reg
move.l %d1,%d2 | save size
fp_get_fp_reg
printf PDECODE,"\n"
addq.l #8,%a0
move.l (%a0),-(%sp)
move.l -(%a0),-(%sp)
move.l -(%a0),-(%sp)
move.l %sp,%a0
jsr fp_normalize_ext
swap %d2
jmp ([0f:w,%pc,%d2.w*4])
.align 4
0:
.long fp_format_long, fp_format_single
.long fp_format_extended, fp_format_packed
.long fp_format_word, fp_format_double
.long fp_format_byte, fp_format_packed
fp_format_long:
jsr fp_conv_ext2long
putuser.l %d0,(%a1),fp_err_ua1,%a1
jra fp_finish_move
fp_format_single:
jsr fp_conv_ext2single
putuser.l %d0,(%a1),fp_err_ua1,%a1
jra fp_finish_move
fp_format_extended:
move.l (%a0)+,%d0
lsl.w #1,%d0
lsl.l #7,%d0
lsl.l #8,%d0
putuser.l %d0,(%a1)+,fp_err_ua1,%a1
move.l (%a0)+,%d0
putuser.l %d0,(%a1)+,fp_err_ua1,%a1
move.l (%a0),%d0
putuser.l %d0,(%a1),fp_err_ua1,%a1
jra fp_finish_move
fp_format_packed:
/* not supported yet */
lea (12,%sp),%sp
jra fp_ill
fp_format_word:
jsr fp_conv_ext2short
putuser.w %d0,(%a1),fp_err_ua1,%a1
jra fp_finish_move
fp_format_double:
jsr fp_conv_ext2double
jra fp_finish_move
fp_format_byte:
jsr fp_conv_ext2byte
putuser.b %d0,(%a1),fp_err_ua1,%a1
| jra fp_finish_move
fp_finish_move:
lea (12,%sp),%sp
jra fp_final
/*
* fp_movem.S
*
* Copyright Roman Zippel, 1997. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, and the entire permission notice in its entirety,
* including the disclaimer of warranties.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* ALTERNATIVELY, this product may be distributed under the terms of
* the GNU Public License, in which case the provisions of the GPL are
* required INSTEAD OF the above restrictions. (This clause is
* necessary due to a potential bad interaction between the GPL and
* the restrictions contained in a BSD-style copyright.)
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fp_emu.h"
#include "fp_decode.h"
| set flags for decode macros for fmovem
do_fmovem=1
.globl fp_fmovem_fp, fp_fmovem_cr
| %d1 contains the mask and count of the register list
| for other register usage see fp_decode.h
fp_fmovem_fp:
printf PDECODE,"fmovem.x "
| get register list and count them
btst #11,%d2
jne 1f
bfextu %d2{#24,#8},%d0 | static register list
jra 2f
1: bfextu %d2{#25,#3},%d0 | dynamic register list
jsr fp_get_data_reg
2: move.l %d0,%d1
swap %d1
jra 2f
1: addq.w #1,%d1 | count the # of registers in
2: lsr.b #1,%d0 | register list and keep it in %d1
jcs 1b
jne 2b
printf PDECODE,"#%08x",1,%d1
#ifdef FPU_EMU_DEBUG
btst #12,%d2
jne 1f
printf PDECODE,"-" | decremental move
jra 2f
1: printf PDECODE,"+" | incremental move
2: btst #13,%d2
jeq 1f
printf PDECODE,"->" | fpu -> cpu
jra 2f
1: printf PDECODE,"<-" | fpu <- cpu
2:
#endif
| decode address mode
fp_decode_addr_mode
.long fp_ill, fp_ill
.long fpr_indirect, fpr_postinc
.long fpr_predecr, fpr_disp16
.long fpr_extmode0, fpr_extmode1
| addressing mode: address register indirect
fpr_indirect:
fp_mode_addr_indirect
jra fpr_do_movem
| addressing mode: address register indirect with postincrement
fpr_postinc:
fp_mode_addr_indirect_postinc
jra fpr_do_movem
fpr_predecr:
fp_mode_addr_indirect_predec
jra fpr_do_movem
| addressing mode: address register/programm counter indirect
| with 16bit displacement
fpr_disp16:
fp_mode_addr_indirect_disp16
jra fpr_do_movem
fpr_extmode0:
fp_mode_addr_indirect_extmode0
jra fpr_do_movem
fpr_extmode1:
fp_decode_addr_reg
jmp ([0f:w,%pc,%d0*4])
.align 4
0:
.long fpr_absolute_short, fpr_absolute_long
.long fpr_disp16, fpr_extmode0
.long fp_ill, fp_ill
.long fp_ill, fp_ill
fpr_absolute_short:
fp_mode_abs_short
jra fpr_do_movem
fpr_absolute_long:
fp_mode_abs_long
| jra fpr_do_movem
fpr_do_movem:
swap %d1 | get fpu register list
lea (FPD_FPREG,FPDATA),%a1
moveq #12,%d0
btst #12,%d2
jne 1f
lea (-12,%a1,%d0*8),%a1
neg.l %d0
1: btst #13,%d2
jne 4f
| move register from memory into fpu
jra 3f
1: printf PMOVEM,"(%p>%p)",2,%a0,%a1
getuser.l (%a0)+,%d2,fp_err_ua1,%a0
lsr.l #8,%d2
lsr.l #7,%d2
lsr.w #1,%d2
move.l %d2,(%a1)+
getuser.l (%a0)+,%d2,fp_err_ua1,%a0
move.l %d2,(%a1)+
getuser.l (%a0),%d2,fp_err_ua1,%a0
move.l %d2,(%a1)
subq.l #8,%a0
subq.l #8,%a1
add.l %d0,%a0
2: add.l %d0,%a1
3: lsl.b #1,%d1
jcs 1b
jne 2b
jra 5f
| move register from fpu into memory
1: printf PMOVEM,"(%p>%p)",2,%a1,%a0
move.l (%a1)+,%d2
lsl.w #1,%d2
lsl.l #7,%d2
lsl.l #8,%d2
putuser.l %d2,(%a0)+,fp_err_ua1,%a0
move.l (%a1)+,%d2
putuser.l %d2,(%a0)+,fp_err_ua1,%a0
move.l (%a1),%d2
putuser.l %d2,(%a0),fp_err_ua1,%a0
subq.l #8,%a1
subq.l #8,%a0
add.l %d0,%a0
2: add.l %d0,%a1
4: lsl.b #1,%d1
jcs 1b
jne 2b
5:
printf PDECODE,"\n"
#if 0
lea (FPD_FPREG,FPDATA),%a0
printf PMOVEM,"fp:"
printx PMOVEM,%a0@(0)
printx PMOVEM,%a0@(12)
printf PMOVEM,"\n "
printx PMOVEM,%a0@(24)
printx PMOVEM,%a0@(36)
printf PMOVEM,"\n "
printx PMOVEM,%a0@(48)
printx PMOVEM,%a0@(60)
printf PMOVEM,"\n "
printx PMOVEM,%a0@(72)
printx PMOVEM,%a0@(84)
printf PMOVEM,"\n"
#endif
jra fp_end
| set flags for decode macros for fmovem control register
do_fmovem=1
do_fmovem_cr=1
fp_fmovem_cr:
printf PDECODE,"fmovem.cr "
| get register list and count them
bfextu %d2{#19,#3},%d0
move.l %d0,%d1
swap %d1
jra 2f
1: addq.w #1,%d1
2: lsr.l #1,%d0
jcs 1b
jne 2b
printf PDECODE,"#%08x",1,%d1
#ifdef FPU_EMU_DEBUG
btst #13,%d2
jeq 1f
printf PDECODE,"->" | fpu -> cpu
jra 2f
1: printf PDECODE,"<-" | fpu <- cpu
2:
#endif
| decode address mode
fp_decode_addr_mode
.long fpc_data, fpc_addr
.long fpc_indirect, fpc_postinc
.long fpc_predecr, fpc_disp16
.long fpc_extmode0, fpc_extmode1
fpc_data:
fp_mode_data_direct
move.w %d0,%d1
bfffo %d2{#19,#3},%d0
sub.w #19,%d0
lea (FPD_FPCR,FPDATA,%d0.w*4),%a1
btst #13,%d2
jne 1f
move.w %d1,%d0
jsr fp_get_data_reg
move.l %d0,(%a1)
jra fpc_movem_fin
1: move.l (%a1),%d0
jsr fp_put_data_reg
jra fpc_movem_fin
fpc_addr:
fp_decode_addr_reg
printf PDECODE,"a%d",1,%d0
btst #13,%d2
jne 1f
jsr fp_get_addr_reg
move.l %a0,(FPD_FPIAR,FPDATA)
jra fpc_movem_fin
1: move.l (FPD_FPIAR,FPDATA),%a0
jsr fp_put_addr_reg
jra fpc_movem_fin
fpc_indirect:
fp_mode_addr_indirect
jra fpc_do_movem
fpc_postinc:
fp_mode_addr_indirect_postinc
jra fpc_do_movem
fpc_predecr:
fp_mode_addr_indirect_predec
jra fpc_do_movem
fpc_disp16:
fp_mode_addr_indirect_disp16
jra fpc_do_movem
fpc_extmode0:
fp_mode_addr_indirect_extmode0
jra fpc_do_movem
fpc_extmode1:
fp_decode_addr_reg
jmp ([0f:w,%pc,%d0*4])
.align 4
0:
.long fpc_absolute_short, fpc_absolute_long
.long fpc_disp16, fpc_extmode0
.long fpc_immediate, fp_ill
.long fp_ill, fp_ill
fpc_absolute_short:
fp_mode_abs_short
jra fpc_do_movem
fpc_absolute_long:
fp_mode_abs_long
jra fpc_do_movem
fpc_immediate:
fp_get_pc %a0
lea (%a0,%d1.w*4),%a1
fp_put_pc %a1
printf PDECODE,"#imm"
| jra fpc_do_movem
#if 0
swap %d1
lsl.l #5,%d1
lea (FPD_FPCR,FPDATA),%a0
jra 3f
1: move.l %d0,(%a0)
2: addq.l #4,%a0
3: lsl.b #1,%d1
jcs 1b
jne 2b
jra fpc_movem_fin
#endif
fpc_do_movem:
swap %d1 | get fpu register list
lsl.l #5,%d1
lea (FPD_FPCR,FPDATA),%a1
1: btst #13,%d2
jne 4f
| move register from memory into fpu
jra 3f
1: printf PMOVEM,"(%p>%p)",2,%a0,%a1
getuser.l (%a0)+,%d0,fp_err_ua1,%a0
move.l %d0,(%a1)
2: addq.l #4,%a1
3: lsl.b #1,%d1
jcs 1b
jne 2b
jra fpc_movem_fin
| move register from fpu into memory
1: printf PMOVEM,"(%p>%p)",2,%a1,%a0
move.l (%a1),%d0
putuser.l %d0,(%a0)+,fp_err_ua1,%a0
2: addq.l #4,%a1
4: lsl.b #1,%d1
jcs 1b
jne 2b
fpc_movem_fin:
and.l #0x0000fff0,(FPD_FPCR,FPDATA)
and.l #0x0ffffff8,(FPD_FPSR,FPDATA)
move.l (FPD_FPCR,FPDATA),%d0
lsr.l #4,%d0
moveq #3,%d1
and.l %d0,%d1
move.w %d1,(FPD_RND,FPDATA)
lsr.l #2,%d0
moveq #3,%d1
and.l %d0,%d1
move.w %d1,(FPD_PREC,FPDATA)
printf PDECODE,"\n"
#if 0
printf PMOVEM,"fpcr : %08x\n",1,FPDATA@(FPD_FPCR)
printf PMOVEM,"fpsr : %08x\n",1,FPDATA@(FPD_FPSR)
printf PMOVEM,"fpiar: %08x\n",1,FPDATA@(FPD_FPIAR)
clr.l %d0
move.w (FPD_PREC,FPDATA),%d0
printf PMOVEM,"prec : %04x\n",1,%d0
move.w (FPD_RND,FPDATA),%d0
printf PMOVEM,"rnd : %04x\n",1,%d0
#endif
jra fp_end
This diff is collapsed.
/*
fp_trig.c: floating-point math routines for the Linux-m68k
floating point emulator.
Copyright (c) 1998-1999 David Huggins-Daines / Roman Zippel.
I hereby give permission, free of charge, to copy, modify, and
redistribute this software, in source or binary form, provided that
the above copyright notice and the following disclaimer are included
in all such copies.
THIS SOFTWARE IS PROVIDED "AS IS", WITH ABSOLUTELY NO WARRANTY, REAL
OR IMPLIED.
*/
#include "fp_emu.h"
#include "fp_trig.h"
struct fp_ext *
fp_fsin(struct fp_ext *dest, struct fp_ext *src)
{
uprint("fsin\n");
fp_monadic_check(dest, src);
return dest;
}
struct fp_ext *
fp_fcos(struct fp_ext *dest, struct fp_ext *src)
{
uprint("fcos\n");
fp_monadic_check(dest, src);
return dest;
}
struct fp_ext *
fp_ftan(struct fp_ext *dest, struct fp_ext *src)
{
uprint("ftan\n");
fp_monadic_check(dest, src);
return dest;
}
struct fp_ext *
fp_fasin(struct fp_ext *dest, struct fp_ext *src)
{
uprint("fasin\n");
fp_monadic_check(dest, src);
return dest;
}
struct fp_ext *
fp_facos(struct fp_ext *dest, struct fp_ext *src)
{
uprint("facos\n");
fp_monadic_check(dest, src);
return dest;
}
struct fp_ext *
fp_fatan(struct fp_ext *dest, struct fp_ext *src)
{
uprint("fatan\n");
fp_monadic_check(dest, src);
return dest;
}
struct fp_ext *
fp_fsinh(struct fp_ext *dest, struct fp_ext *src)
{
uprint("fsinh\n");
fp_monadic_check(dest, src);
return dest;
}
struct fp_ext *
fp_fcosh(struct fp_ext *dest, struct fp_ext *src)
{
uprint("fcosh\n");
fp_monadic_check(dest, src);
return dest;
}
struct fp_ext *
fp_ftanh(struct fp_ext *dest, struct fp_ext *src)
{
uprint("ftanh\n");
fp_monadic_check(dest, src);
return dest;
}
struct fp_ext *
fp_fatanh(struct fp_ext *dest, struct fp_ext *src)
{
uprint("fatanh\n");
fp_monadic_check(dest, src);
return dest;
}
struct fp_ext *
fp_fsincos0(struct fp_ext *dest, struct fp_ext *src)
{
uprint("fsincos0\n");
return dest;
}
struct fp_ext *
fp_fsincos1(struct fp_ext *dest, struct fp_ext *src)
{
uprint("fsincos1\n");
return dest;
}
struct fp_ext *
fp_fsincos2(struct fp_ext *dest, struct fp_ext *src)
{
uprint("fsincos2\n");
return dest;
}
struct fp_ext *
fp_fsincos3(struct fp_ext *dest, struct fp_ext *src)
{
uprint("fsincos3\n");
return dest;
}
struct fp_ext *
fp_fsincos4(struct fp_ext *dest, struct fp_ext *src)
{
uprint("fsincos4\n");
return dest;
}
struct fp_ext *
fp_fsincos5(struct fp_ext *dest, struct fp_ext *src)
{
uprint("fsincos5\n");
return dest;
}
struct fp_ext *
fp_fsincos6(struct fp_ext *dest, struct fp_ext *src)
{
uprint("fsincos6\n");
return dest;
}
struct fp_ext *
fp_fsincos7(struct fp_ext *dest, struct fp_ext *src)
{
uprint("fsincos7\n");
return dest;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -380,7 +380,7 @@ register_busmouse(struct busmouse *ops)
if (busmouse_data[msedev])
return -EBUSY;
mse = kmalloc(GFP_KERNEL, sizeof(*mse));
mse = kmalloc(sizeof(*mse), GFP_KERNEL);
if (!mse)
return -ENOMEM;
......@@ -465,6 +465,7 @@ bus_mouse_init(void))
return 0;
}
EXPORT_SYMBOL(busmouse_add_movementbuttons);
EXPORT_SYMBOL(busmouse_add_movement);
EXPORT_SYMBOL(busmouse_add_buttons);
EXPORT_SYMBOL(register_busmouse);
......
This diff is collapsed.
......@@ -47,7 +47,6 @@
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
......
......@@ -34,7 +34,6 @@
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment