Commit 3579bc6f authored by Linus Torvalds's avatar Linus Torvalds

[PATCH] Linux-0.99.9 (April 23, 1993)

Bill's math emulator now passes paranoia.

Last argument to ioctl is "long".

sys_clone() appears.

[original announcement below]

The latest kernel release is 0.99.9, and can be found on nic.funet.fi:
pub/OS/Linux/PEOPLE/Linus, both as patches relative to pl8 and as full
sources.  The only major new feature is that the ST-0x driver has
finally been updated to the scatter-gather code: ST-0x users should with
luck get about 5 times the performance on disk-operations..  Seagate
code written by Drew Eckhardt.

0.99.9 also fixes:
- the FPU-emulator should now handle all rounding-modes correctly, and
  pass all the paranoia package tests.  Patches by Bill Metzenthen.
- bootup enhancements by Chrisoph Niemann (but the SVGA mode numbers
  have changed, so you may have to edit your lilo configuration file
  and/or the main Makefile to get the mode you normally want)
- ext2fs updated to the very latest release.  Code by Remy Card and
  Stephen Tweedie.
- various minor patches, some of them cosmetic, some of them fixes to
  smaller bugs..  Thanks to everybody who sent them in (even though not
  all made it)

It might be a good idea to test it all out,

            Linus
parent a2858ced
...@@ -68,7 +68,7 @@ KEYBOARD = -DKBD_FINNISH -DKBDFLAGS=0 ...@@ -68,7 +68,7 @@ KEYBOARD = -DKBD_FINNISH -DKBDFLAGS=0
# The number is the same as you would ordinarily press at bootup. # The number is the same as you would ordinarily press at bootup.
# #
SVGA_MODE= -DSVGA_MODE=1 SVGA_MODE= -DSVGA_MODE=3
# #
# standard CFLAGS # standard CFLAGS
...@@ -139,7 +139,7 @@ tools/./version.h: tools/version.h ...@@ -139,7 +139,7 @@ tools/./version.h: tools/version.h
tools/version.h: $(CONFIGURE) Makefile tools/version.h: $(CONFIGURE) Makefile
@./makever.sh @./makever.sh
@echo \#define UTS_RELEASE \"0.99.pl8-`cat .version`\" > tools/version.h @echo \#define UTS_RELEASE \"0.99.pl9-`cat .version`\" > tools/version.h
@echo \#define UTS_VERSION \"`date +%D`\" >> tools/version.h @echo \#define UTS_VERSION \"`date +%D`\" >> tools/version.h
@echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> tools/version.h @echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> tools/version.h
@echo \#define LINUX_COMPILE_BY \"`whoami`\" >> tools/version.h @echo \#define LINUX_COMPILE_BY \"`whoami`\" >> tools/version.h
......
This diff is collapsed.
...@@ -14,8 +14,8 @@ ...@@ -14,8 +14,8 @@
.s.o: .s.o:
$(AS) -o $*.o $< $(AS) -o $*.o $<
OBJS= balloc.o bitmap.o dcache.o dir.o file.o ialloc.o inode.o \ OBJS= acl.o balloc.o bitmap.o dcache.o dir.o file.o ialloc.o inode.o \
namei.o symlink.o truncate.o ioctl.o namei.o symlink.o truncate.o
ext2.o: $(OBJS) ext2.o: $(OBJS)
$(LD) -r -o ext2.o $(OBJS) $(LD) -r -o ext2.o $(OBJS)
......
/*
* linux/fs/ext2/acl.c
*
* Copyright (C) 1993 Remy Card (card@masi.ibp.fr)
*/
/*
* This file will contain the Access Control Lists management for the
* second extended file system.
*/
#include <linux/sched.h>
#include <linux/ext2_fs.h>
#include <linux/errno.h>
/*
* ext2_permission ()
*
* Check for access rights
*/
int ext2_permission (struct inode * inode, int mask)
{
int mode = inode->i_mode;
/* Special case, access is always granted for root */
if (suser ())
return 1;
/* If no ACL, checks using the file mode */
else if (current->euid == inode->i_uid)
mode >>= 6;
else if (in_group_p (inode->i_gid))
mode >>= 3;
if (((mode & mask & 0007) == mask))
return 1;
else
return 0;
}
...@@ -38,31 +38,32 @@ ...@@ -38,31 +38,32 @@
:"a" (0), "c" (size/4), "D" ((long) (addr)) \ :"a" (0), "c" (size/4), "D" ((long) (addr)) \
:"cx", "di") :"cx", "di")
static inline int find_first_zero_bit(unsigned *addr, unsigned size) static inline int find_first_zero_bit (unsigned *addr, unsigned size)
{ {
int res; int res;
if (!size) if (!size)
return 0; return 0;
__asm__(" __asm__("
cld cld
movl $-1,%%eax movl $-1,%%eax
repe; scasl repe; scasl
je 1f je 1f
subl $4,%%edi subl $4,%%edi
movl (%%edi),%%eax movl (%%edi),%%eax
notl %%eax notl %%eax
bsfl %%eax,%%edx bsfl %%eax,%%edx
jmp 2f jmp 2f
1: xorl %%edx,%%edx 1: xorl %%edx,%%edx
2: subl %%ebx,%%edi 2: subl %%ebx,%%edi
shll $3,%%edi shll $3,%%edi
addl %%edi,%%edx" addl %%edi,%%edx"
:"=d" (res):"c" ((size+31)>>5), "D" (addr), "b" (addr) :"=d" (res)
:"ax", "bx", "cx", "di"); :"c" ((size+31)>>5), "D" (addr), "b" (addr)
:"ax", "bx", "cx", "di");
return res; return res;
} }
static inline int find_next_zero_bit(unsigned *addr, int size, int offset) static inline int find_next_zero_bit (unsigned * addr, int size, int offset)
{ {
unsigned *p = ((unsigned *) addr) + (offset >> 5); unsigned *p = ((unsigned *) addr) + (offset >> 5);
int set = 0, bit = offset & 31, res; int set = 0, bit = offset & 31, res;
...@@ -70,32 +71,37 @@ static inline int find_next_zero_bit(unsigned *addr, int size, int offset) ...@@ -70,32 +71,37 @@ static inline int find_next_zero_bit(unsigned *addr, int size, int offset)
if (bit) { if (bit) {
/* Look for zero in first byte */ /* Look for zero in first byte */
__asm__(" __asm__("
bsfl %1,%0 bsfl %1,%0
jne 1f jne 1f
movl $32, %0 movl $32, %0
1: " : "=r" (set) : "r" (~(*p >> bit))); 1: "
if (set < (32-bit)) : "=r" (set)
: "r" (~(*p >> bit)));
if (set < (32 - bit))
return set + offset; return set + offset;
set = 32-bit; set = 32 - bit;
p++; p++;
} }
/* No zero yet, search remaining full bytes for a zero */ /* No zero yet, search remaining full bytes for a zero */
res = find_first_zero_bit(p, size-32*(p-addr)); res = find_first_zero_bit (p, size - 32 * (p - addr));
return (offset + set + res); return (offset + set + res);
} }
static inline char * find_first_zero_byte(char *addr,int size) static inline char * find_first_zero_byte (char * addr, int size)
{ {
char *res; char *res;
if (!size) if (!size)
return 0; return 0;
__asm__(" __asm__("
cld cld
mov $0,%%eax mov $0,%%eax
repnz; scasb repnz; scasb
jnz 1f jnz 1f
dec %%edi dec %%edi
1: " : "=D" (res) : "0" (addr), "c" (size) : "ax"); 1: "
: "=D" (res)
: "0" (addr), "c" (size)
: "ax");
return res; return res;
} }
...@@ -155,8 +161,8 @@ static int load__block_bitmap (struct super_block * sb, ...@@ -155,8 +161,8 @@ static int load__block_bitmap (struct super_block * sb,
if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED) { if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED) {
if (sb->u.ext2_sb.s_block_bitmap[block_group]) { if (sb->u.ext2_sb.s_block_bitmap[block_group]) {
if (sb->u.ext2_sb.s_block_bitmap_number[block_group] if (sb->u.ext2_sb.s_block_bitmap_number[block_group] !=
!= block_group) block_group)
panic ("load_block_bitmap: " panic ("load_block_bitmap: "
"block_group != block_bitmap_number"); "block_group != block_bitmap_number");
else else
...@@ -189,7 +195,7 @@ static int load__block_bitmap (struct super_block * sb, ...@@ -189,7 +195,7 @@ static int load__block_bitmap (struct super_block * sb,
else else
brelse (sb->u.ext2_sb.s_block_bitmap brelse (sb->u.ext2_sb.s_block_bitmap
[EXT2_MAX_GROUP_LOADED - 1]); [EXT2_MAX_GROUP_LOADED - 1]);
for (j = sb->u.ext2_sb.s_loaded_block_bitmaps-1; j>0; j--) { for (j = sb->u.ext2_sb.s_loaded_block_bitmaps - 1; j > 0; j--) {
sb->u.ext2_sb.s_block_bitmap_number[j] = sb->u.ext2_sb.s_block_bitmap_number[j] =
sb->u.ext2_sb.s_block_bitmap_number[j - 1]; sb->u.ext2_sb.s_block_bitmap_number[j - 1];
sb->u.ext2_sb.s_block_bitmap[j] = sb->u.ext2_sb.s_block_bitmap[j] =
...@@ -337,14 +343,12 @@ int ext2_new_block (struct super_block * sb, unsigned long goal) ...@@ -337,14 +343,12 @@ int ext2_new_block (struct super_block * sb, unsigned long goal)
bitmap_nr = load_block_bitmap (sb, i); bitmap_nr = load_block_bitmap (sb, i);
bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr]; bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
if (!bh) { if (!bh) {
printk ("Cannot load bitmap_nr %d.\n", printk ("Cannot load bitmap_nr %d.\n", bitmap_nr);
bitmap_nr);
unlock_super (sb); unlock_super (sb);
return 0; return 0;
} }
#ifdef EXT2FS_DEBUG #ifdef EXT2FS_DEBUG
printk ("goal is at %d[%d,%d]:%d.\n", printk ("goal is at %d[%d,%d]:%d.\n", i, group_desc, desc, j);
i, group_desc, desc, j);
#endif #endif
if (!test_bit(j, bh->b_data)) { if (!test_bit(j, bh->b_data)) {
#ifdef EXT2FS_DEBUG #ifdef EXT2FS_DEBUG
...@@ -356,14 +360,18 @@ int ext2_new_block (struct super_block * sb, unsigned long goal) ...@@ -356,14 +360,18 @@ int ext2_new_block (struct super_block * sb, unsigned long goal)
if (j) { if (j) {
/* The goal was occupied; search forward for a free /* The goal was occupied; search forward for a free
block within the next 32 blocks */ block within the next 32 blocks */
lmap = (((((unsigned long *) bh->b_data)[j >> 5]) lmap = ((((unsigned long *) bh->b_data)[j >> 5]) >>
>> ((j&31)+1)) | ((j & 31) + 1));
((((unsigned long *) bh->b_data)[(j>>5)+1]) if (j < EXT2_BLOCKS_PER_GROUP(sb) - 32)
<<(31-(j&31)))); lmap |= (((unsigned long *) bh->b_data)[(j >> 5) + 1]) <<
(31 - (j & 31));
else
lmap |= 0xffffffff << (31 - (j & 31));
if (lmap != 0xffffffffl) { if (lmap != 0xffffffffl) {
__asm__ ("bsfl %1,%0" : __asm__ ("bsfl %1,%0"
"=r" (k) : : "=r" (k)
"r" (~lmap)); k++; : "r" (~lmap));
k++;
if ((j + k) < EXT2_BLOCKS_PER_GROUP(sb)) { if ((j + k) < EXT2_BLOCKS_PER_GROUP(sb)) {
j += k; j += k;
goto got_block; goto got_block;
...@@ -381,9 +389,9 @@ int ext2_new_block (struct super_block * sb, unsigned long goal) ...@@ -381,9 +389,9 @@ int ext2_new_block (struct super_block * sb, unsigned long goal)
Search first in the remainder of the current group; then, Search first in the remainder of the current group; then,
cyclicly search throught the rest of the groups. */ cyclicly search throught the rest of the groups. */
p = ((char *) bh->b_data) + (j>>3); p = ((char *) bh->b_data) + (j >> 3);
r = find_first_zero_byte (p, r = find_first_zero_byte (p,
(EXT2_BLOCKS_PER_GROUP(sb)-j+7)>>3); (EXT2_BLOCKS_PER_GROUP(sb) - j + 7) >> 3);
k = (r - ((char *) bh->b_data)) << 3; k = (r - ((char *) bh->b_data)) << 3;
if (k < EXT2_BLOCKS_PER_GROUP(sb)) { if (k < EXT2_BLOCKS_PER_GROUP(sb)) {
j = k; j = k;
...@@ -440,7 +448,7 @@ int ext2_new_block (struct super_block * sb, unsigned long goal) ...@@ -440,7 +448,7 @@ int ext2_new_block (struct super_block * sb, unsigned long goal)
} }
r = find_first_zero_byte (bh->b_data, r = find_first_zero_byte (bh->b_data,
EXT2_BLOCKS_PER_GROUP(sb) >> 3); EXT2_BLOCKS_PER_GROUP(sb) >> 3);
j = (r-bh->b_data) << 3; j = (r - bh->b_data) << 3;
if (j >= EXT2_BLOCKS_PER_GROUP(sb)) if (j >= EXT2_BLOCKS_PER_GROUP(sb))
j = find_first_zero_bit ((unsigned long *) bh->b_data, j = find_first_zero_bit ((unsigned long *) bh->b_data,
EXT2_BLOCKS_PER_GROUP(sb)); EXT2_BLOCKS_PER_GROUP(sb));
...@@ -466,8 +474,7 @@ int ext2_new_block (struct super_block * sb, unsigned long goal) ...@@ -466,8 +474,7 @@ int ext2_new_block (struct super_block * sb, unsigned long goal)
#ifdef EXT2FS_DEBUG #ifdef EXT2FS_DEBUG
printk ("ext2_new_block: found bit %d\n", j); printk ("ext2_new_block: found bit %d\n", j);
#endif #endif
j += i * EXT2_BLOCKS_PER_GROUP(sb) + j += i * EXT2_BLOCKS_PER_GROUP(sb) + sb->u.ext2_sb.s_first_data_block;
sb->u.ext2_sb.s_first_data_block;
if (j >= sb->u.ext2_sb.s_blocks_count) { if (j >= sb->u.ext2_sb.s_blocks_count) {
printk ("block_group = %d,block=%d\n", i, j); printk ("block_group = %d,block=%d\n", i, j);
printk ("ext2_new_block: block >= blocks count"); printk ("ext2_new_block: block >= blocks count");
......
...@@ -6,6 +6,9 @@ ...@@ -6,6 +6,9 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/ext2_fs.h>
#ifdef EXT2FS_DEBUG
static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0}; static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
...@@ -21,3 +24,5 @@ unsigned long ext2_count_free (struct buffer_head * map, unsigned numchars) ...@@ -21,3 +24,5 @@ unsigned long ext2_count_free (struct buffer_head * map, unsigned numchars)
nibblemap[(map->b_data[i] >> 4) & 0xf]; nibblemap[(map->b_data[i] >> 4) & 0xf];
return (sum); return (sum);
} }
#endif
...@@ -37,7 +37,7 @@ static struct file_operations ext2_dir_operations = { ...@@ -37,7 +37,7 @@ static struct file_operations ext2_dir_operations = {
NULL, /* write - bad */ NULL, /* write - bad */
ext2_readdir, /* readdir */ ext2_readdir, /* readdir */
NULL, /* select - default */ NULL, /* select - default */
NULL, /* ioctl - default */ ext2_ioctl, /* ioctl */
NULL, /* mmap */ NULL, /* mmap */
NULL, /* no special open code */ NULL, /* no special open code */
NULL, /* no special release code */ NULL, /* no special release code */
...@@ -61,8 +61,8 @@ struct inode_operations ext2_dir_inode_operations = { ...@@ -61,8 +61,8 @@ struct inode_operations ext2_dir_inode_operations = {
NULL, /* readlink */ NULL, /* readlink */
NULL, /* follow_link */ NULL, /* follow_link */
NULL, /* bmap */ NULL, /* bmap */
ext2_truncate, /* truncate */ ext2_truncate, /* truncate */
NULL /* permission */ ext2_permission /* permission */
}; };
int ext2_check_dir_entry (char * function, struct inode * dir, int ext2_check_dir_entry (char * function, struct inode * dir,
...@@ -93,17 +93,17 @@ int ext2_check_dir_entry (char * function, struct inode * dir, ...@@ -93,17 +93,17 @@ int ext2_check_dir_entry (char * function, struct inode * dir,
static int ext2_readdir (struct inode * inode, struct file * filp, static int ext2_readdir (struct inode * inode, struct file * filp,
struct dirent * dirent, int count) struct dirent * dirent, int count)
{ {
unsigned int offset, i; unsigned int offset, i, err;
struct buffer_head * bh; struct buffer_head * bh;
struct ext2_dir_entry * de; struct ext2_dir_entry * de;
struct super_block * sb; struct super_block * sb;
if (!inode || !S_ISDIR(inode->i_mode)) if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF; return -EBADF;
sb = inode->i_sb; sb = inode->i_sb;
while (filp->f_pos < inode->i_size) { while (filp->f_pos < inode->i_size) {
offset = filp->f_pos & (sb->s_blocksize - 1); offset = filp->f_pos & (sb->s_blocksize - 1);
bh = ext2_bread (inode, (filp->f_pos) >> EXT2_BLOCK_SIZE_BITS(sb), 0); bh = ext2_bread (inode, (filp->f_pos) >> EXT2_BLOCK_SIZE_BITS(sb), 0, &err);
if (!bh) { if (!bh) {
filp->f_pos += sb->s_blocksize - offset; filp->f_pos += sb->s_blocksize - offset;
continue; continue;
......
...@@ -44,7 +44,7 @@ static struct file_operations ext2_file_operations = { ...@@ -44,7 +44,7 @@ static struct file_operations ext2_file_operations = {
ext2_file_write, /* write */ ext2_file_write, /* write */
NULL, /* readdir - bad */ NULL, /* readdir - bad */
NULL, /* select - default */ NULL, /* select - default */
NULL, /* ioctl - default */ ext2_ioctl, /* ioctl - default */
NULL, /* mmap */ NULL, /* mmap */
NULL, /* no special open is needed */ NULL, /* no special open is needed */
NULL, /* release */ NULL, /* release */
...@@ -66,7 +66,7 @@ struct inode_operations ext2_file_inode_operations = { ...@@ -66,7 +66,7 @@ struct inode_operations ext2_file_inode_operations = {
NULL, /* follow_link */ NULL, /* follow_link */
ext2_bmap, /* bmap */ ext2_bmap, /* bmap */
ext2_truncate, /* truncate */ ext2_truncate, /* truncate */
NULL /* permission */ ext2_permission /* permission */
}; };
/* static */ int ext2_file_read (struct inode * inode, struct file * filp, /* static */ int ext2_file_read (struct inode * inode, struct file * filp,
...@@ -79,7 +79,7 @@ struct inode_operations ext2_file_inode_operations = { ...@@ -79,7 +79,7 @@ struct inode_operations ext2_file_inode_operations = {
struct buffer_head * bhreq[NBUF]; struct buffer_head * bhreq[NBUF];
struct buffer_head * buflist[NBUF]; struct buffer_head * buflist[NBUF];
struct super_block * sb; struct super_block * sb;
unsigned int size; unsigned int size, err;
if (!inode) { if (!inode) {
printk ("ext2_file_read: inode = NULL\n"); printk ("ext2_file_read: inode = NULL\n");
...@@ -127,7 +127,7 @@ struct inode_operations ext2_file_inode_operations = { ...@@ -127,7 +127,7 @@ struct inode_operations ext2_file_inode_operations = {
uptodate = 1; uptodate = 1;
while (blocks) { while (blocks) {
--blocks; --blocks;
*bhb = ext2_getblk (inode, block++, 0); *bhb = ext2_getblk (inode, block++, 0, &err);
if (*bhb && !(*bhb)->b_uptodate) { if (*bhb && !(*bhb)->b_uptodate) {
uptodate = 0; uptodate = 0;
bhreq[bhrequest++] = *bhb; bhreq[bhrequest++] = *bhb;
...@@ -203,6 +203,7 @@ static int ext2_file_write (struct inode * inode, struct file * filp, ...@@ -203,6 +203,7 @@ static int ext2_file_write (struct inode * inode, struct file * filp,
struct buffer_head * bh; struct buffer_head * bh;
char * p; char * p;
struct super_block * sb; struct super_block * sb;
int err;
if (!inode) { if (!inode) {
printk("ext2_file_write: inode = NULL\n"); printk("ext2_file_write: inode = NULL\n");
...@@ -223,13 +224,13 @@ static int ext2_file_write (struct inode * inode, struct file * filp, ...@@ -223,13 +224,13 @@ static int ext2_file_write (struct inode * inode, struct file * filp,
pos = filp->f_pos; pos = filp->f_pos;
written = 0; written = 0;
while (written < count) { while (written < count) {
bh = ext2_getblk (inode, pos / sb->s_blocksize, 1); bh = ext2_getblk (inode, pos / sb->s_blocksize, 1, &err);
if (!bh) { if (!bh) {
#ifdef EXT2FS_DEBUG #ifdef EXT2FS_DEBUG
printk ("ext2_file_write: ext2_getblk returned NULL\n"); printk ("ext2_file_write: ext2_getblk returned NULL\n");
#endif #endif
if (!written) if (!written)
written = -ENOSPC; written = err;
break; break;
} }
c = sb->s_blocksize - (pos % sb->s_blocksize); c = sb->s_blocksize - (pos % sb->s_blocksize);
......
...@@ -32,27 +32,28 @@ ...@@ -32,27 +32,28 @@
#include <asm/bitops.h> #include <asm/bitops.h>
static inline int find_first_zero_bit(unsigned *addr, unsigned size) static inline int find_first_zero_bit(unsigned * addr, unsigned size)
{ {
int res; int res;
if (!size) if (!size)
return 0; return 0;
__asm__(" __asm__("
cld cld
movl $-1,%%eax movl $-1,%%eax
repe; scasl repe; scasl
je 1f je 1f
subl $4,%%edi subl $4,%%edi
movl (%%edi),%%eax movl (%%edi),%%eax
notl %%eax notl %%eax
bsfl %%eax,%%edx bsfl %%eax,%%edx
jmp 2f jmp 2f
1: xorl %%edx,%%edx 1: xorl %%edx,%%edx
2: subl %%ebx,%%edi 2: subl %%ebx,%%edi
shll $3,%%edi shll $3,%%edi
addl %%edi,%%edx" addl %%edi,%%edx"
:"=d" (res):"c" ((size+31)>>5), "D" (addr), "b" (addr) : "=d" (res)
:"ax", "bx", "cx", "di"); :"c" ((size + 31) >> 5), "D" (addr), "b" (addr)
: "ax", "bx", "cx", "di");
return res; return res;
} }
...@@ -289,17 +290,16 @@ static void inc_inode_version (struct inode * inode, ...@@ -289,17 +290,16 @@ static void inc_inode_version (struct inode * inode,
EXT2_INODES_PER_GROUP(inode->i_sb)) % EXT2_INODES_PER_GROUP(inode->i_sb)) %
EXT2_INODES_PER_BLOCK(inode->i_sb)); EXT2_INODES_PER_BLOCK(inode->i_sb));
raw_inode->i_version++; raw_inode->i_version++;
if (!S_ISFIFO(mode)) inode->u.ext2_i.i_version = raw_inode->i_version;
inode->u.ext2_i.i_version = raw_inode->i_version;
bh->b_dirt = 1; bh->b_dirt = 1;
brelse (bh); brelse (bh);
} }
static struct ext2_group_desc * static struct ext2_group_desc * get_group_desc(struct super_block * sb,
get_group_desc(struct super_block *sb, int group) int group)
{ {
struct ext2_group_desc * gdp; struct ext2_group_desc * gdp;
if (group >= sb->u.ext2_sb.s_groups_count || group < 0 ) if (group >= sb->u.ext2_sb.s_groups_count || group < 0 )
panic ("ext2: get_group_desc: Invalid group\n"); panic ("ext2: get_group_desc: Invalid group\n");
if (!sb->u.ext2_sb.s_group_desc[group / EXT2_DESC_PER_BLOCK(sb)]) if (!sb->u.ext2_sb.s_group_desc[group / EXT2_DESC_PER_BLOCK(sb)])
panic ("ext2: get_group_desc: Descriptor not loaded"); panic ("ext2: get_group_desc: Descriptor not loaded");
...@@ -340,7 +340,7 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode) ...@@ -340,7 +340,7 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
gdp = NULL; i=0; gdp = NULL; i=0;
if (S_ISDIR(mode)) { if (S_ISDIR(mode)) {
avefreei = es->s_free_inodes_count / avefreei = es->s_free_inodes_count /
sb->u.ext2_sb.s_groups_count; sb->u.ext2_sb.s_groups_count;
/* I am not yet convinced that this next bit is necessary. /* I am not yet convinced that this next bit is necessary.
i = dir->u.ext2_i.i_block_group; i = dir->u.ext2_i.i_block_group;
...@@ -377,11 +377,11 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode) ...@@ -377,11 +377,11 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
gdp = tmp; gdp = tmp;
else else
{ /* Use a quadratic hash to find a group with a free inode */ { /* Use a quadratic hash to find a group with a free inode */
for (j=1; j<sb->u.ext2_sb.s_groups_count; j<<=1) { for (j = 1; j < sb->u.ext2_sb.s_groups_count; j <<= 1) {
i+=j; i += j;
if (i>=sb->u.ext2_sb.s_groups_count) if (i >= sb->u.ext2_sb.s_groups_count)
i-=sb->u.ext2_sb.s_groups_count; i -= sb->u.ext2_sb.s_groups_count;
tmp = get_group_desc(sb,i); tmp = get_group_desc(sb, i);
if (tmp->bg_free_inodes_count) { if (tmp->bg_free_inodes_count) {
gdp = tmp; gdp = tmp;
break; break;
...@@ -391,9 +391,9 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode) ...@@ -391,9 +391,9 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
if (!gdp) { if (!gdp) {
/* That failed: try linear search for a free inode */ /* That failed: try linear search for a free inode */
i = dir->u.ext2_i.i_block_group + 2; i = dir->u.ext2_i.i_block_group + 2;
for (j=2; j<sb->u.ext2_sb.s_groups_count; j++) { for (j = 2; j < sb->u.ext2_sb.s_groups_count; j++) {
if (++i > sb->u.ext2_sb.s_groups_count) if (++i >= sb->u.ext2_sb.s_groups_count)
i=0; i = 0;
tmp = get_group_desc(sb,i); tmp = get_group_desc(sb,i);
if (tmp->bg_free_inodes_count) { if (tmp->bg_free_inodes_count) {
gdp = tmp; gdp = tmp;
...@@ -454,8 +454,7 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode) ...@@ -454,8 +454,7 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
inode->u.ext2_i.i_file_acl = 0; inode->u.ext2_i.i_file_acl = 0;
inode->u.ext2_i.i_dir_acl = 0; inode->u.ext2_i.i_dir_acl = 0;
inode->u.ext2_i.i_dtime = 0; inode->u.ext2_i.i_dtime = 0;
if (!S_ISFIFO(mode)) inode->u.ext2_i.i_block_group = i;
inode->u.ext2_i.i_block_group = i;
inode->i_op = NULL; inode->i_op = NULL;
inc_inode_version (inode, gdp, mode); inc_inode_version (inode, gdp, mode);
#ifdef EXT2FS_DEBUG #ifdef EXT2FS_DEBUG
......
This diff is collapsed.
/*
* linux/fs/ext2/ioctl.c
*
* Copyright (C) 1993 Remy Card (card@masi.ibp.fr)
*/
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/ext2_fs.h>
int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
unsigned long arg)
{
#ifdef EXT2FS_DEBUG
printk ("ext2_ioctl: cmd = %d, arg = %d\n", cmd, arg);
#endif
return -EINVAL;
}
This diff is collapsed.
...@@ -72,7 +72,7 @@ static int ext2_follow_link(struct inode * dir, struct inode * inode, ...@@ -72,7 +72,7 @@ static int ext2_follow_link(struct inode * dir, struct inode * inode,
return -ELOOP; return -ELOOP;
} }
if (inode->i_blocks) { if (inode->i_blocks) {
if (!(bh = ext2_bread (inode, 0, 0))) { if (!(bh = ext2_bread (inode, 0, 0, &error))) {
iput (dir); iput (dir);
iput (inode); iput (inode);
return -EIO; return -EIO;
...@@ -93,7 +93,7 @@ static int ext2_readlink (struct inode * inode, char * buffer, int buflen) ...@@ -93,7 +93,7 @@ static int ext2_readlink (struct inode * inode, char * buffer, int buflen)
{ {
struct buffer_head * bh = NULL; struct buffer_head * bh = NULL;
char * link; char * link;
int i; int i, err;
char c; char c;
if (!S_ISLNK(inode->i_mode)) { if (!S_ISLNK(inode->i_mode)) {
...@@ -103,7 +103,7 @@ static int ext2_readlink (struct inode * inode, char * buffer, int buflen) ...@@ -103,7 +103,7 @@ static int ext2_readlink (struct inode * inode, char * buffer, int buflen)
if (buflen > inode->i_sb->s_blocksize - 1) if (buflen > inode->i_sb->s_blocksize - 1)
buflen = inode->i_sb->s_blocksize - 1; buflen = inode->i_sb->s_blocksize - 1;
if (inode->i_blocks) { if (inode->i_blocks) {
bh = ext2_bread (inode, 0, 0); bh = ext2_bread (inode, 0, 0, &err);
if (!bh) { if (!bh) {
iput (inode); iput (inode);
return 0; return 0;
......
...@@ -9,6 +9,12 @@ ...@@ -9,6 +9,12 @@
struct file file_table[NR_FILE]; struct file file_table[NR_FILE];
unsigned long file_table_init(unsigned long start, unsigned long end)
{
memset(file_table,0,sizeof(file_table));
return start;
}
struct file * get_empty_filp(void) struct file * get_empty_filp(void)
{ {
int i; int i;
......
...@@ -11,15 +11,13 @@ ...@@ -11,15 +11,13 @@
int int
isonum_711 (p) isonum_711 (char * p)
char *p;
{ {
return (*p & 0xff); return (*p & 0xff);
} }
int int
isonum_712 (p) isonum_712 (char * p)
char *p;
{ {
int val; int val;
...@@ -30,22 +28,19 @@ char *p; ...@@ -30,22 +28,19 @@ char *p;
} }
int int
isonum_721 (p) isonum_721 (char * p)
char *p;
{ {
return ((p[0] & 0xff) | ((p[1] & 0xff) << 8)); return ((p[0] & 0xff) | ((p[1] & 0xff) << 8));
} }
int int
isonum_722 (p) isonum_722 (char * p)
char *p;
{ {
return (((p[0] & 0xff) << 8) | (p[1] & 0xff)); return (((p[0] & 0xff) << 8) | (p[1] & 0xff));
} }
int int
isonum_723 (p) isonum_723 (char * p)
char *p;
{ {
#if 0 #if 0
if (p[0] != p[3] || p[1] != p[2]) { if (p[0] != p[3] || p[1] != p[2]) {
...@@ -57,8 +52,7 @@ char *p; ...@@ -57,8 +52,7 @@ char *p;
} }
int int
isonum_731 (p) isonum_731 (char * p)
char *p;
{ {
return ((p[0] & 0xff) return ((p[0] & 0xff)
| ((p[1] & 0xff) << 8) | ((p[1] & 0xff) << 8)
...@@ -67,8 +61,7 @@ char *p; ...@@ -67,8 +61,7 @@ char *p;
} }
int int
isonum_732 (p) isonum_732 (char * p)
char *p;
{ {
return (((p[0] & 0xff) << 24) return (((p[0] & 0xff) << 24)
| ((p[1] & 0xff) << 16) | ((p[1] & 0xff) << 16)
...@@ -77,8 +70,7 @@ char *p; ...@@ -77,8 +70,7 @@ char *p;
} }
int int
isonum_733 (p) isonum_733 (char * p)
char *p;
{ {
#if 0 #if 0
int i; int i;
...@@ -93,9 +85,7 @@ char *p; ...@@ -93,9 +85,7 @@ char *p;
return (isonum_731 (p)); return (isonum_731 (p));
} }
int iso_date(p, flag) int iso_date(char * p, int flag)
char * p;
int flag;
{ {
int year, month, day, hour ,minute, second, tz; int year, month, day, hour ,minute, second, tz;
int crtime, days, i; int crtime, days, i;
......
...@@ -183,9 +183,7 @@ static int dir_namei(const char * pathname, int * namelen, const char ** name, ...@@ -183,9 +183,7 @@ static int dir_namei(const char * pathname, int * namelen, const char ** name,
if (!c) if (!c)
break; break;
base->i_count++; base->i_count++;
((char *) thisname)[len] = '\0'; /* fake string.. */
error = lookup(base,thisname,len,&inode); error = lookup(base,thisname,len,&inode);
((char *) thisname)[len] = c;
if (error) { if (error) {
iput(base); iput(base);
return error; return error;
......
...@@ -283,11 +283,12 @@ static void nfs_lookup_cache_refresh(struct inode *file, ...@@ -283,11 +283,12 @@ static void nfs_lookup_cache_refresh(struct inode *file,
} }
} }
static int nfs_lookup(struct inode *dir, const char *name, int len, static int nfs_lookup(struct inode *dir, const char *__name, int len,
struct inode **result) struct inode **result)
{ {
struct nfs_fh fhandle; struct nfs_fh fhandle;
struct nfs_fattr fattr; struct nfs_fattr fattr;
char name[len > NFS_MAXNAMLEN? 1 : len+1];
int error; int error;
*result = NULL; *result = NULL;
...@@ -300,6 +301,8 @@ static int nfs_lookup(struct inode *dir, const char *name, int len, ...@@ -300,6 +301,8 @@ static int nfs_lookup(struct inode *dir, const char *name, int len,
iput(dir); iput(dir);
return -ENAMETOOLONG; return -ENAMETOOLONG;
} }
memcpy(name,__name,len);
name[len] = '\0';
if (len == 1 && name[0] == '.') { /* cheat for "." */ if (len == 1 && name[0] == '.') { /* cheat for "." */
*result = dir; *result = dir;
return 0; return 0;
......
...@@ -167,11 +167,11 @@ int sys_access(const char * filename,int mode) ...@@ -167,11 +167,11 @@ int sys_access(const char * filename,int mode)
return res; return res;
i_mode = inode->i_mode; i_mode = inode->i_mode;
res = i_mode & 0777; res = i_mode & 0777;
iput(inode);
if (current->uid == inode->i_uid) if (current->uid == inode->i_uid)
res >>= 6; res >>= 6;
else if (in_group_p(inode->i_gid)) else if (in_group_p(inode->i_gid))
res >>= 3; res >>= 3;
iput(inode);
if ((res & mode) == mode) if ((res & mode) == mode)
return 0; return 0;
/* /*
......
...@@ -108,7 +108,7 @@ static int bad_pipe_rw(struct inode * inode, struct file * filp, char * buf, int ...@@ -108,7 +108,7 @@ static int bad_pipe_rw(struct inode * inode, struct file * filp, char * buf, int
} }
static int pipe_ioctl(struct inode *pino, struct file * filp, static int pipe_ioctl(struct inode *pino, struct file * filp,
unsigned int cmd, unsigned int arg) unsigned int cmd, unsigned long arg)
{ {
int error; int error;
......
...@@ -81,23 +81,30 @@ int do_select(int n, fd_set *in, fd_set *out, fd_set *ex, ...@@ -81,23 +81,30 @@ int do_select(int n, fd_set *in, fd_set *out, fd_set *ex,
int count; int count;
select_table wait_table, *wait; select_table wait_table, *wait;
struct select_table_entry *entry; struct select_table_entry *entry;
int i; unsigned long set;
int max; int i,j;
int max = -1;
max = -1;
for (i = 0 ; i < n ; i++) { for (j = 0 ; j < __FDSET_LONGS ; j++) {
if (!FD_ISSET(i, in) && i = j << 5;
!FD_ISSET(i, out) && if (i >= n)
!FD_ISSET(i, ex)) break;
continue; set = in->fds_bits[j] | out->fds_bits[j] | ex->fds_bits[j];
if (!current->filp[i]) for ( ; set ; i++,set >>= 1) {
return -EBADF; if (i >= n)
if (!current->filp[i]->f_inode) goto end_check;
return -EBADF; if (!(set & 1))
max = i; continue;
if (!current->filp[i])
return -EBADF;
if (!current->filp[i]->f_inode)
return -EBADF;
max = i;
}
} }
end_check:
n = max + 1; n = max + 1;
entry = (struct select_table_entry *) get_free_page(GFP_KERNEL); entry = (struct select_table_entry *) __get_free_page(GFP_KERNEL);
if (!entry) if (!entry)
return -ENOMEM; return -ENOMEM;
FD_ZERO(res_in); FD_ZERO(res_in);
...@@ -182,6 +189,9 @@ __set_fd_set(nr, (unsigned long *) (fsp), (unsigned long *) (fdp)) ...@@ -182,6 +189,9 @@ __set_fd_set(nr, (unsigned long *) (fsp), (unsigned long *) (fdp))
* We can actually return ERESTARTSYS insetad of EINTR, but I'd * We can actually return ERESTARTSYS insetad of EINTR, but I'd
* like to be certain this leads to no problems. So I return * like to be certain this leads to no problems. So I return
* EINTR just for safety. * EINTR just for safety.
*
* Update: ERESTARTSYS breaks at least the xview clock binary, so
* I'm trying ERESTARTNOHAND which restart only when you want to.
*/ */
int sys_select( unsigned long *buffer ) int sys_select( unsigned long *buffer )
{ {
...@@ -236,7 +246,7 @@ int sys_select( unsigned long *buffer ) ...@@ -236,7 +246,7 @@ int sys_select( unsigned long *buffer )
if (i < 0) if (i < 0)
return i; return i;
if (!i && (current->signal & ~current->blocked)) if (!i && (current->signal & ~current->blocked))
return -EINTR; return -ERESTARTNOHAND;
set_fd_set(n, inp, &res_in); set_fd_set(n, inp, &res_in);
set_fd_set(n, outp, &res_out); set_fd_set(n, outp, &res_out);
set_fd_set(n, exp, &res_ex); set_fd_set(n, exp, &res_ex);
......
...@@ -379,9 +379,12 @@ int sys_mount(char * dev_name, char * dir_name, char * type, ...@@ -379,9 +379,12 @@ int sys_mount(char * dev_name, char * dir_name, char * type,
return do_remount(dir_name,new_flags & ~MS_MGC_MSK & ~MS_REMOUNT); return do_remount(dir_name,new_flags & ~MS_MGC_MSK & ~MS_REMOUNT);
} }
if (type) { if (type) {
for (i = 0 ; i < 100 ; i++) for (i = 0 ; i < 100 ; i++) {
if (TASK_SIZE <= (unsigned long) type)
return -EFAULT;
if (!(tmp[i] = get_fs_byte(type++))) if (!(tmp[i] = get_fs_byte(type++)))
break; break;
}
t = tmp; t = tmp;
} else } else
t = NULL; t = NULL;
...@@ -446,7 +449,6 @@ void mount_root(void) ...@@ -446,7 +449,6 @@ void mount_root(void)
struct super_block * sb; struct super_block * sb;
struct inode * inode; struct inode * inode;
memset(file_table, 0, sizeof(file_table));
memset(super_block, 0, sizeof(super_block)); memset(super_block, 0, sizeof(super_block));
fcntl_init_locks(); fcntl_init_locks();
if (MAJOR(ROOT_DEV) == 2) { if (MAJOR(ROOT_DEV) == 2) {
......
...@@ -20,7 +20,7 @@ struct __dummy { unsigned long a[100]; }; ...@@ -20,7 +20,7 @@ struct __dummy { unsigned long a[100]; };
extern inline int set_bit(int nr, void * addr) extern inline int set_bit(int nr, void * addr)
{ {
char ok; unsigned char ok;
__asm__ __volatile__("btsl %2,%1\n\tsetb %0" __asm__ __volatile__("btsl %2,%1\n\tsetb %0"
:"=q" (ok),"=m" (ADDR) :"=q" (ok),"=m" (ADDR)
...@@ -30,7 +30,7 @@ extern inline int set_bit(int nr, void * addr) ...@@ -30,7 +30,7 @@ extern inline int set_bit(int nr, void * addr)
extern inline int clear_bit(int nr, void * addr) extern inline int clear_bit(int nr, void * addr)
{ {
char ok; unsigned char ok;
__asm__ __volatile__("btrl %2,%1\n\tsetnb %0" __asm__ __volatile__("btrl %2,%1\n\tsetnb %0"
:"=q" (ok),"=m" (ADDR) :"=q" (ok),"=m" (ADDR)
...@@ -44,7 +44,7 @@ extern inline int clear_bit(int nr, void * addr) ...@@ -44,7 +44,7 @@ extern inline int clear_bit(int nr, void * addr)
*/ */
extern inline int test_bit(int nr, void * addr) extern inline int test_bit(int nr, void * addr)
{ {
char ok; unsigned char ok;
__asm__ __volatile__("btl %2,%1\n\tsetb %0" __asm__ __volatile__("btl %2,%1\n\tsetb %0"
:"=q" (ok) :"=q" (ok)
......
...@@ -247,9 +247,11 @@ static __inline__ int get_dma_residue(unsigned int dmanr) ...@@ -247,9 +247,11 @@ static __inline__ int get_dma_residue(unsigned int dmanr)
: ((dmanr&3)<<2) + 2 + IO_DMA2_BASE; : ((dmanr&3)<<2) + 2 + IO_DMA2_BASE;
/* using short to get 16-bit wrap around */ /* using short to get 16-bit wrap around */
short count = 1 + inb(io_port) + unsigned short count;
( inb(io_port) << 8 );
count = 1 + inb(io_port);
count += inb(io_port) << 8;
return (dmanr<=3)? count : (count<<1); return (dmanr<=3)? count : (count<<1);
} }
......
extern inline unsigned char get_fs_byte(const char * addr) static inline unsigned char get_fs_byte(const char * addr)
{ {
register unsigned char _v; register unsigned char _v;
...@@ -6,7 +6,7 @@ extern inline unsigned char get_fs_byte(const char * addr) ...@@ -6,7 +6,7 @@ extern inline unsigned char get_fs_byte(const char * addr)
return _v; return _v;
} }
extern inline unsigned short get_fs_word(const unsigned short *addr) static inline unsigned short get_fs_word(const unsigned short *addr)
{ {
unsigned short _v; unsigned short _v;
...@@ -14,7 +14,7 @@ extern inline unsigned short get_fs_word(const unsigned short *addr) ...@@ -14,7 +14,7 @@ extern inline unsigned short get_fs_word(const unsigned short *addr)
return _v; return _v;
} }
extern inline unsigned long get_fs_long(const unsigned long *addr) static inline unsigned long get_fs_long(const unsigned long *addr)
{ {
unsigned long _v; unsigned long _v;
...@@ -22,22 +22,22 @@ extern inline unsigned long get_fs_long(const unsigned long *addr) ...@@ -22,22 +22,22 @@ extern inline unsigned long get_fs_long(const unsigned long *addr)
return _v; return _v;
} }
extern inline void put_fs_byte(char val,char *addr) static inline void put_fs_byte(char val,char *addr)
{ {
__asm__ ("movb %0,%%fs:%1"::"q" (val),"m" (*addr)); __asm__ ("movb %0,%%fs:%1"::"q" (val),"m" (*addr));
} }
extern inline void put_fs_word(short val,short * addr) static inline void put_fs_word(short val,short * addr)
{ {
__asm__ ("movw %0,%%fs:%1"::"r" (val),"m" (*addr)); __asm__ ("movw %0,%%fs:%1"::"r" (val),"m" (*addr));
} }
extern inline void put_fs_long(unsigned long val,unsigned long * addr) static inline void put_fs_long(unsigned long val,unsigned long * addr)
{ {
__asm__ ("movl %0,%%fs:%1"::"r" (val),"m" (*addr)); __asm__ ("movl %0,%%fs:%1"::"r" (val),"m" (*addr));
} }
extern inline void memcpy_tofs(void * to, const void * from, unsigned long n) static inline void memcpy_tofs(void * to, const void * from, unsigned long n)
{ {
__asm__("cld\n\t" __asm__("cld\n\t"
"push %%es\n\t" "push %%es\n\t"
...@@ -56,7 +56,7 @@ __asm__("cld\n\t" ...@@ -56,7 +56,7 @@ __asm__("cld\n\t"
:"cx","di","si"); :"cx","di","si");
} }
extern inline void memcpy_fromfs(void * to, const void * from, unsigned long n) static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
{ {
__asm__("cld\n\t" __asm__("cld\n\t"
"testb $1,%%cl\n\t" "testb $1,%%cl\n\t"
...@@ -78,21 +78,21 @@ __asm__("cld\n\t" ...@@ -78,21 +78,21 @@ __asm__("cld\n\t"
* [ nothing wrong here, Linus: I just changed the ax to be any reg ] * [ nothing wrong here, Linus: I just changed the ax to be any reg ]
*/ */
extern inline unsigned long get_fs(void) static inline unsigned long get_fs(void)
{ {
unsigned short _v; unsigned short _v;
__asm__("mov %%fs,%0":"=r" (_v):); __asm__("mov %%fs,%0":"=r" (_v):);
return _v; return _v;
} }
extern inline unsigned long get_ds(void) static inline unsigned long get_ds(void)
{ {
unsigned short _v; unsigned short _v;
__asm__("mov %%ds,%0":"=r" (_v):); __asm__("mov %%ds,%0":"=r" (_v):);
return _v; return _v;
} }
extern inline void set_fs(unsigned long val) static inline void set_fs(unsigned long val)
{ {
__asm__ __volatile__("mov %0,%%fs"::"r" ((unsigned short) val)); __asm__ __volatile__("mov %0,%%fs"::"r" ((unsigned short) val));
} }
......
...@@ -10,6 +10,11 @@ ...@@ -10,6 +10,11 @@
*/ */
#undef EXT2FS_DEBUG #undef EXT2FS_DEBUG
/*
* Define EXT2FS_PRE_02B_COMPAT to convert ext 2 fs prior to 0.2b
*/
#undef EXT2FS_PRE_02B_COMPAT
/* /*
* Define DONT_USE_DCACHE to inhibit the directory cache * Define DONT_USE_DCACHE to inhibit the directory cache
*/ */
...@@ -23,7 +28,7 @@ ...@@ -23,7 +28,7 @@
/* /*
* The second extended file system version * The second extended file system version
*/ */
#define EXT2FS_VERSION "0.2d, 93/03/30" #define EXT2FS_VERSION "0.3, 93/04/22"
/* /*
* Special inodes numbers * Special inodes numbers
...@@ -39,6 +44,11 @@ ...@@ -39,6 +44,11 @@
#define EXT2_OLD_SUPER_MAGIC 0xEF51 #define EXT2_OLD_SUPER_MAGIC 0xEF51
#define EXT2_SUPER_MAGIC 0xEF53 #define EXT2_SUPER_MAGIC 0xEF53
/*
* Maximal count of links to a file
*/
#define EXT2_LINK_MAX 32000
/* /*
* Macro-instructions used to manage several block sizes * Macro-instructions used to manage several block sizes
*/ */
...@@ -50,6 +60,7 @@ ...@@ -50,6 +60,7 @@
#else #else
# define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size) # define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
#endif #endif
#define EXT2_ACLE_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry))
#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (unsigned long)) #define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (unsigned long))
#ifdef KERNEL #ifdef KERNEL
# define EXT2_BLOCK_SIZE_BITS(s) ((s)->u.ext2_sb.s_log_block_size + 10) # define EXT2_BLOCK_SIZE_BITS(s) ((s)->u.ext2_sb.s_log_block_size + 10)
...@@ -72,6 +83,29 @@ ...@@ -72,6 +83,29 @@
# define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s)) # define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s))
#endif #endif
/*
* ACL structures
*/
struct ext2_acl_header /* Header of Access Control Lists */
{
unsigned long aclh_file_count;
unsigned long aclh_acle_count;
unsigned long aclh_first_acle;
unsigned long aclh_reserved;
};
struct ext2_acl_entry /* Access Control List Entry */
{
unsigned short acle_perms; /* Access permissions */
unsigned short acle_type; /* Type of entry */
unsigned short acle_tag; /* User or group identity */
unsigned short acle_pad1;
unsigned long acle_reserved;
unsigned long acle_next; /* Pointer on next entry for the */
/* same inode or on next free entry */
};
/* /*
* Structure of a blocks group descriptor * Structure of a blocks group descriptor
*/ */
...@@ -196,6 +230,9 @@ struct ext2_dir_entry { ...@@ -196,6 +230,9 @@ struct ext2_dir_entry {
* Function prototypes * Function prototypes
*/ */
/* acl.c */
extern int ext2_permission (struct inode *, int);
/* balloc.c */ /* balloc.c */
extern int ext2_new_block (struct super_block *, unsigned long); extern int ext2_new_block (struct super_block *, unsigned long);
extern void ext2_free_block (struct super_block *, unsigned long); extern void ext2_free_block (struct super_block *, unsigned long);
...@@ -230,10 +267,9 @@ extern unsigned long ext2_count_free_inodes (struct super_block *); ...@@ -230,10 +267,9 @@ extern unsigned long ext2_count_free_inodes (struct super_block *);
/* inode.c */ /* inode.c */
extern int ext2_bmap (struct inode *, int); extern int ext2_bmap (struct inode *, int);
extern struct buffer_head * ext2_getblk (struct inode *, int, int); extern struct buffer_head * ext2_getblk (struct inode *, int, int, int *);
extern struct buffer_head * ext2_bread (struct inode *, int, int); extern struct buffer_head * ext2_bread (struct inode *, int, int, int *);
extern void ext2_truncate (struct inode *);
extern void ext2_put_super (struct super_block *); extern void ext2_put_super (struct super_block *);
extern void ext2_write_super (struct super_block *); extern void ext2_write_super (struct super_block *);
extern struct super_block * ext2_read_super (struct super_block *,void *,int); extern struct super_block * ext2_read_super (struct super_block *,void *,int);
...@@ -242,6 +278,10 @@ extern void ext2_write_inode (struct inode *); ...@@ -242,6 +278,10 @@ extern void ext2_write_inode (struct inode *);
extern void ext2_put_inode (struct inode *); extern void ext2_put_inode (struct inode *);
extern void ext2_statfs (struct super_block *, struct statfs *); extern void ext2_statfs (struct super_block *, struct statfs *);
/* ioctl.c */
extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
unsigned long);
/* namei.c */ /* namei.c */
extern int ext2_open (struct inode *, struct file *); extern int ext2_open (struct inode *, struct file *);
extern void ext2_release (struct inode *, struct file *); extern void ext2_release (struct inode *, struct file *);
...@@ -257,6 +297,9 @@ extern int ext2_mknod (struct inode *, const char *, int, int, int); ...@@ -257,6 +297,9 @@ extern int ext2_mknod (struct inode *, const char *, int, int, int);
extern int ext2_rename (struct inode *, const char *, int, extern int ext2_rename (struct inode *, const char *, int,
struct inode *, const char *, int); struct inode *, const char *, int);
/* truncate.c */
extern void ext2_truncate (struct inode *);
/* /*
* Inodes and files operations * Inodes and files operations
*/ */
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* second extended file system inode data in memory * second extended file system inode data in memory
*/ */
struct ext2_inode_info { struct ext2_inode_info {
unsigned long i_data[15];
unsigned long i_flags; unsigned long i_flags;
unsigned long i_faddr; unsigned long i_faddr;
unsigned char i_frag; unsigned char i_frag;
...@@ -17,7 +18,6 @@ struct ext2_inode_info { ...@@ -17,7 +18,6 @@ struct ext2_inode_info {
unsigned long i_block_group; unsigned long i_block_group;
unsigned long i_next_alloc_block; unsigned long i_next_alloc_block;
unsigned long i_next_alloc_goal; unsigned long i_next_alloc_goal;
unsigned long i_data[15];
}; };
#endif #endif
...@@ -21,10 +21,10 @@ ...@@ -21,10 +21,10 @@
* recompiled to take full advantage of the new limits.. * recompiled to take full advantage of the new limits..
*/ */
#undef NR_OPEN #undef NR_OPEN
#define NR_OPEN 256 #define NR_OPEN 256 /* don't change - fd_set etc depend on this */
#define NR_INODE 256 #define NR_INODE 256 /* this should be bigger than NR_FILE */
#define NR_FILE 128 #define NR_FILE 128 /* this can well be larger on a larger system */
#define NR_SUPER 16 #define NR_SUPER 16
#define NR_HASH 997 #define NR_HASH 997
#define NR_FILE_LOCKS 32 #define NR_FILE_LOCKS 32
...@@ -67,6 +67,7 @@ ...@@ -67,6 +67,7 @@
extern void buffer_init(void); extern void buffer_init(void);
extern unsigned long inode_init(unsigned long start, unsigned long end); extern unsigned long inode_init(unsigned long start, unsigned long end);
extern unsigned long file_table_init(unsigned long start, unsigned long end);
#define MAJOR(a) (((unsigned)(a))>>8) #define MAJOR(a) (((unsigned)(a))>>8)
#define MINOR(a) ((a)&0xff) #define MINOR(a) ((a)&0xff)
...@@ -264,7 +265,7 @@ struct file_operations { ...@@ -264,7 +265,7 @@ struct file_operations {
int (*write) (struct inode *, struct file *, char *, int); int (*write) (struct inode *, struct file *, char *, int);
int (*readdir) (struct inode *, struct file *, struct dirent *, int); int (*readdir) (struct inode *, struct file *, struct dirent *, int);
int (*select) (struct inode *, struct file *, int, select_table *); int (*select) (struct inode *, struct file *, int, select_table *);
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned int); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
int (*mmap) (struct inode *, struct file *, unsigned long, size_t, int, unsigned long); int (*mmap) (struct inode *, struct file *, unsigned long, size_t, int, unsigned long);
int (*open) (struct inode *, struct file *); int (*open) (struct inode *, struct file *);
void (*release) (struct inode *, struct file *); void (*release) (struct inode *, struct file *);
......
...@@ -65,6 +65,7 @@ extern struct kbd_struct kbd_table[]; ...@@ -65,6 +65,7 @@ extern struct kbd_struct kbd_table[];
#define VC_RAW 7 /* raw (scancode) mode */ #define VC_RAW 7 /* raw (scancode) mode */
#define VC_CRLF 8 /* 0 - enter sends CR, 1 - enter sends CRLF */ #define VC_CRLF 8 /* 0 - enter sends CR, 1 - enter sends CRLF */
#define VC_META 9 /* 0 - meta, 1 - meta=prefix with ESC */ #define VC_META 9 /* 0 - meta, 1 - meta=prefix with ESC */
#define VC_PAUSE 10 /* pause key pressed */
#define LED_MASK 7 #define LED_MASK 7
......
...@@ -92,6 +92,7 @@ extern unsigned long put_dirty_page(struct task_struct * tsk,unsigned long page, ...@@ -92,6 +92,7 @@ extern unsigned long put_dirty_page(struct task_struct * tsk,unsigned long page,
extern void free_page_tables(struct task_struct * tsk); extern void free_page_tables(struct task_struct * tsk);
extern void clear_page_tables(struct task_struct * tsk); extern void clear_page_tables(struct task_struct * tsk);
extern int copy_page_tables(struct task_struct * new); extern int copy_page_tables(struct task_struct * new);
extern int clone_page_tables(struct task_struct * new);
extern int unmap_page_range(unsigned long from, unsigned long size); extern int unmap_page_range(unsigned long from, unsigned long size);
extern int remap_page_range(unsigned long from, unsigned long to, unsigned long size, int mask); extern int remap_page_range(unsigned long from, unsigned long to, unsigned long size, int mask);
extern int zeromap_page_range(unsigned long from, unsigned long size, int mask); extern int zeromap_page_range(unsigned long from, unsigned long size, int mask);
......
...@@ -149,6 +149,7 @@ struct task_struct { ...@@ -149,6 +149,7 @@ struct task_struct {
unsigned long signal; unsigned long signal;
unsigned long blocked; /* bitmap of masked signals */ unsigned long blocked; /* bitmap of masked signals */
unsigned long flags; /* per process flags, defined below */ unsigned long flags; /* per process flags, defined below */
int errno;
/* various fields */ /* various fields */
struct sigaction sigaction[32]; struct sigaction sigaction[32];
unsigned long saved_kernel_stack; unsigned long saved_kernel_stack;
...@@ -220,7 +221,7 @@ struct task_struct { ...@@ -220,7 +221,7 @@ struct task_struct {
* your own risk!. Base=0, limit=0x1fffff (=2MB) * your own risk!. Base=0, limit=0x1fffff (=2MB)
*/ */
#define INIT_TASK \ #define INIT_TASK \
/* state etc */ { 0,15,15,0,0,0, \ /* state etc */ { 0,15,15,0,0,0,0, \
/* signals */ {{ 0, },}, \ /* signals */ {{ 0, },}, \
/* stack */ 0,0, \ /* stack */ 0,0, \
/* ec,brk... */ 0,0,0,0,0,0,0,0, \ /* ec,brk... */ 0,0,0,0,0,0,0,0, \
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
* Why isn't this a .c file? Enquiring minds.... * Why isn't this a .c file? Enquiring minds....
*/ */
#define sys_clone sys_fork
extern int sys_setup(); extern int sys_setup();
extern int sys_exit(); extern int sys_exit();
extern int sys_fork(); extern int sys_fork();
...@@ -144,7 +146,8 @@ sys_ftruncate, sys_fchmod, sys_fchown, sys_getpriority, sys_setpriority, ...@@ -144,7 +146,8 @@ sys_ftruncate, sys_fchmod, sys_fchown, sys_getpriority, sys_setpriority,
sys_profil, sys_statfs, sys_fstatfs, sys_ioperm, sys_socketcall, sys_profil, sys_statfs, sys_fstatfs, sys_ioperm, sys_socketcall,
sys_syslog, sys_setitimer, sys_getitimer, sys_newstat, sys_newlstat, sys_syslog, sys_setitimer, sys_getitimer, sys_newstat, sys_newlstat,
sys_newfstat, sys_newuname, sys_iopl, sys_vhangup, sys_idle, sys_vm86, sys_newfstat, sys_newuname, sys_iopl, sys_vhangup, sys_idle, sys_vm86,
sys_wait4, sys_swapoff, sys_sysinfo, sys_ipc, sys_fsync, sys_sigreturn }; sys_wait4, sys_swapoff, sys_sysinfo, sys_ipc, sys_fsync, sys_sigreturn,
sys_clone };
/* So we don't have to do any more manual updating.... */ /* So we don't have to do any more manual updating.... */
int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr); int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr);
...@@ -138,6 +138,7 @@ extern int get_tty_queue(struct tty_queue * queue); ...@@ -138,6 +138,7 @@ extern int get_tty_queue(struct tty_queue * queue);
#define QUIT_CHAR(tty) ((tty)->termios->c_cc[VQUIT]) #define QUIT_CHAR(tty) ((tty)->termios->c_cc[VQUIT])
#define ERASE_CHAR(tty) ((tty)->termios->c_cc[VERASE]) #define ERASE_CHAR(tty) ((tty)->termios->c_cc[VERASE])
#define KILL_CHAR(tty) ((tty)->termios->c_cc[VKILL]) #define KILL_CHAR(tty) ((tty)->termios->c_cc[VKILL])
#define WERASE_CHAR(tty) ((tty)->termios->c_cc[VWERASE])
#define EOF_CHAR(tty) ((tty)->termios->c_cc[VEOF]) #define EOF_CHAR(tty) ((tty)->termios->c_cc[VEOF])
#define START_CHAR(tty) ((tty)->termios->c_cc[VSTART]) #define START_CHAR(tty) ((tty)->termios->c_cc[VSTART])
#define STOP_CHAR(tty) ((tty)->termios->c_cc[VSTOP]) #define STOP_CHAR(tty) ((tty)->termios->c_cc[VSTOP])
...@@ -213,7 +214,7 @@ struct tty_struct { ...@@ -213,7 +214,7 @@ struct tty_struct {
void (*close)(struct tty_struct * tty, struct file * filp); void (*close)(struct tty_struct * tty, struct file * filp);
void (*write)(struct tty_struct * tty); void (*write)(struct tty_struct * tty);
int (*ioctl)(struct tty_struct *tty, struct file * file, int (*ioctl)(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned int arg); unsigned int cmd, unsigned long arg);
void (*throttle)(struct tty_struct * tty, int status); void (*throttle)(struct tty_struct * tty, int status);
void (*set_termios)(struct tty_struct *tty, struct termios * old); void (*set_termios)(struct tty_struct *tty, struct termios * old);
struct tty_struct *link; struct tty_struct *link;
...@@ -239,7 +240,7 @@ struct tty_ldisc { ...@@ -239,7 +240,7 @@ struct tty_ldisc {
int (*write)(struct tty_struct * tty, struct file * file, int (*write)(struct tty_struct * tty, struct file * file,
char * buf, int nr); char * buf, int nr);
int (*ioctl)(struct tty_struct * tty, struct file * file, int (*ioctl)(struct tty_struct * tty, struct file * file,
unsigned int cmd, unsigned int arg); unsigned int cmd, unsigned long arg);
/* /*
* The following routines are called from below. * The following routines are called from below.
*/ */
...@@ -340,7 +341,7 @@ extern void wait_until_sent(struct tty_struct * tty); ...@@ -340,7 +341,7 @@ extern void wait_until_sent(struct tty_struct * tty);
extern void copy_to_cooked(struct tty_struct * tty); extern void copy_to_cooked(struct tty_struct * tty);
extern int tty_register_ldisc(int disc, struct tty_ldisc *new); extern int tty_register_ldisc(int disc, struct tty_ldisc *new);
extern int tty_ioctl(struct inode *, struct file *, unsigned int, unsigned int); extern int tty_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
extern int is_orphaned_pgrp(int pgrp); extern int is_orphaned_pgrp(int pgrp);
extern int is_ignored(int sig); extern int is_ignored(int sig);
extern int tty_signal(int sig, struct tty_struct *tty); extern int tty_signal(int sig, struct tty_struct *tty);
...@@ -375,6 +376,6 @@ extern void unblank_screen(void); ...@@ -375,6 +376,6 @@ extern void unblank_screen(void);
/* vt.c */ /* vt.c */
extern int vt_ioctl(struct tty_struct *tty, struct file * file, extern int vt_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned int arg); unsigned int cmd, unsigned long arg);
#endif #endif
...@@ -126,6 +126,7 @@ ...@@ -126,6 +126,7 @@
#define __NR_ipc 117 /* not implemented yet */ #define __NR_ipc 117 /* not implemented yet */
#define __NR_fsync 118 /* not implemented yet */ #define __NR_fsync 118 /* not implemented yet */
#define __NR_sigreturn 119 #define __NR_sigreturn 119
#define __NR_clone 120
extern int errno; extern int errno;
......
...@@ -114,7 +114,7 @@ static void xd_geninit (void); ...@@ -114,7 +114,7 @@ static void xd_geninit (void);
static int xd_open (struct inode *inode,struct file *file); static int xd_open (struct inode *inode,struct file *file);
static void do_xd_request (void); static void do_xd_request (void);
static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned int arg); static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg);
static void xd_release (struct inode *inode,struct file *file); static void xd_release (struct inode *inode,struct file *file);
static int xd_reread_partitions (int dev); static int xd_reread_partitions (int dev);
static int xd_readwrite (u_char operation,u_char drive,u_char *buffer,u_int block,u_int count); static int xd_readwrite (u_char operation,u_char drive,u_char *buffer,u_int block,u_int count);
......
...@@ -198,7 +198,15 @@ static void parse_options(char *line) ...@@ -198,7 +198,15 @@ static void parse_options(char *line)
if (!strcmp(line,"rw")) { if (!strcmp(line,"rw")) {
root_mountflags &= ~MS_RDONLY; root_mountflags &= ~MS_RDONLY;
continue; continue;
} }
if (!strcmp(line,"no387")) {
hard_math = 0;
__asm__("movl %%cr0,%%eax\n\t"
"andl $0xFFFFFFF9,%%eax\n\t"
"orl $0x4,%%eax\n\t"
"movl %%eax,%%cr0\n\t" ::: "ax");
continue;
}
/* /*
* Then check if it's an environment variable or * Then check if it's an environment variable or
* an option. * an option.
...@@ -275,6 +283,7 @@ void start_kernel(void) ...@@ -275,6 +283,7 @@ void start_kernel(void)
memory_start = scsi_dev_init(memory_start,memory_end); memory_start = scsi_dev_init(memory_start,memory_end);
#endif #endif
memory_start = inode_init(memory_start,memory_end); memory_start = inode_init(memory_start,memory_end);
memory_start = file_table_init(memory_start,memory_end);
mem_init(low_memory_start,memory_start,memory_end); mem_init(low_memory_start,memory_start,memory_end);
buffer_init(); buffer_init();
time_init(); time_init();
......
...@@ -19,15 +19,15 @@ OBJS = fpu_entry.o ...@@ -19,15 +19,15 @@ OBJS = fpu_entry.o
ifdef CONFIG_MATH_EMULATION ifdef CONFIG_MATH_EMULATION
OBJS := $(OBJS) div_small.o errors.o\ OBJS := $(OBJS) div_small.o errors.o \
fpu_arith.o fpu_aux.o fpu_etc.o fpu_trig.o\ fpu_arith.o fpu_aux.o fpu_etc.o fpu_trig.o \
load_store.o get_address.o\ load_store.o get_address.o \
poly_atan.o poly_l2.o poly_2xm1.o poly_sin.o poly_tan.o\ poly_atan.o poly_l2.o poly_2xm1.o poly_sin.o poly_tan.o \
poly_div.o poly_mul64.o polynomial.o\ poly_div.o poly_mul64.o polynomial.o \
precision.o\ reg_add_sub.o reg_compare.o reg_constant.o reg_ld_str.o \
reg_add_sub.o reg_compare.o reg_constant.o reg_ld_str.o\
reg_div.o reg_mul.o reg_norm.o \ reg_div.o reg_mul.o reg_norm.o \
reg_u_add.o reg_u_div.o reg_u_mul.o reg_u_sub.o\ reg_u_add.o reg_u_div.o reg_u_mul.o reg_u_sub.o \
reg_round.o \
wm_shrx.o wm_sqrt.o wm_shrx.o wm_sqrt.o
endif endif
......
...@@ -83,7 +83,7 @@ is confined to five files: ...@@ -83,7 +83,7 @@ is confined to five files:
----------------------- Limitations of wm-FPU-emu ----------------------- ----------------------- Limitations of wm-FPU-emu -----------------------
There are a number of differences between the current wm-FPU-emu There are a number of differences between the current wm-FPU-emu
(version beta 1.2) and the 80486 FPU (apart from bugs). Some of the (version beta 1.3) and the 80486 FPU (apart from bugs). Some of the
more important differences are listed below: more important differences are listed below:
Internal computations do not use de-normal numbers (but External Internal computations do not use de-normal numbers (but External
...@@ -91,12 +91,11 @@ de-normals ARE recognised and generated). The design of wm-FPU-emu ...@@ -91,12 +91,11 @@ de-normals ARE recognised and generated). The design of wm-FPU-emu
allows a larger exponent range than the 80486 FPU for internal allows a larger exponent range than the 80486 FPU for internal
computations. computations.
All computations are performed at full 64 bit precision with `round to All internal computations are performed at 64 bit or higher precision.
nearest or even' performed for the basic functions. The results of the The results of the basic arithmetic functions and sqrt are then
basic arithmetic functions and sqrt are then rounded to lower rounded to the precision required by the PC bits of the FPU control
precision if required by the PC bits of the FPU control word. Under word. Under the crt0 version for Linux current at March 1993, the FPU
the crt0 version for Linux current at March 1993, the FPU PC bits PC bits specify 53 bits precision.
specify 53 bits precision.
The precision flag (PE of the FPU status word) is not implemented. The precision flag (PE of the FPU status word) is not implemented.
Does anyone write code which uses this feature? Does anyone write code which uses this feature?
...@@ -193,3 +192,12 @@ tan(x) 1e-10 .. pi/2-(1e-10) 62.4 (x <= pi/4) 62.1 ...@@ -193,3 +192,12 @@ tan(x) 1e-10 .. pi/2-(1e-10) 62.4 (x <= pi/4) 62.1
exp(x) 0 .. 1 63.1 62.9 exp(x) 0 .. 1 63.1 62.9
log(x) 1+1e-6 .. 2 62.4 62.1 log(x) 1+1e-6 .. 2 62.4 62.1
As of version 1.3 of the emulator, the accuracy of the basic
arithmetic has been improved (by a small fraction of a bit). Care has
been taken to ensure full accuracy of the rounding of the basic
arithmetic functions (+,-,*,/,and fsqrt), and they all now produce
results which are exact to the 64th bit (unless there are any bugs
left). To ensure this, it was necessary to effectively get information
of up to about 128 bits precision. The emulator now passes the
"paranoia" tests.
...@@ -33,20 +33,9 @@ ...@@ -33,20 +33,9 @@
/* p 15-5: Precision control bits affect only the following: /* p 15-5: Precision control bits affect only the following:
ADD, SUB(R), MUL, DIV(R), and SQRT */ ADD, SUB(R), MUL, DIV(R), and SQRT */
#define PRECISION_ADJUST_CONTROL (control_word & 0x300) #define FULL_PRECISION (CW_PC | RC_RND)
#define PR_24_BITS 0x000 #define PR_24_BITS _Const_(0x000)
#define PR_53_BITS 0x200 #define PR_53_BITS _Const_(0x200)
/* By doing this as a macro, we allow easy modification */ #define PR_64_BITS _Const_(0x300)
#define PRECISION_ADJUST(x) \
switch (PRECISION_ADJUST_CONTROL) \
{ \
case PR_24_BITS: \
round_to_24_bits(x); \
break; \
case PR_53_BITS: \
round_to_53_bits(x); \
break; \
}
#endif _CONTROLW_H_ #endif _CONTROLW_H_
...@@ -18,16 +18,14 @@ ...@@ -18,16 +18,14 @@
void fadd__() void fadd__()
{ {
/* fadd st,st(i) */ /* fadd st,st(i) */
reg_add(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr); reg_add(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
PRECISION_ADJUST(FPU_st0_ptr);
} }
void fmul__() void fmul__()
{ {
/* fmul st,st(i) */ /* fmul st,st(i) */
reg_mul(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr); reg_mul(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
PRECISION_ADJUST(FPU_st0_ptr);
} }
...@@ -35,32 +33,28 @@ void fmul__() ...@@ -35,32 +33,28 @@ void fmul__()
void fsub__() void fsub__()
{ {
/* fsub st,st(i) */ /* fsub st,st(i) */
reg_sub(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr); reg_sub(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
PRECISION_ADJUST(FPU_st0_ptr);
} }
void fsubr_() void fsubr_()
{ {
/* fsubr st,st(i) */ /* fsubr st,st(i) */
reg_sub(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr); reg_sub(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr, control_word);
PRECISION_ADJUST(FPU_st0_ptr);
} }
void fdiv__() void fdiv__()
{ {
/* fdiv st,st(i) */ /* fdiv st,st(i) */
reg_div(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr); reg_div(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
PRECISION_ADJUST(FPU_st0_ptr);
} }
void fdivr_() void fdivr_()
{ {
/* fdivr st,st(i) */ /* fdivr st,st(i) */
reg_div(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr); reg_div(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr, control_word);
PRECISION_ADJUST(FPU_st0_ptr);
} }
...@@ -68,16 +62,14 @@ void fdivr_() ...@@ -68,16 +62,14 @@ void fdivr_()
void fadd_i() void fadd_i()
{ {
/* fadd st(i),st */ /* fadd st(i),st */
reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm)); reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
PRECISION_ADJUST(&st(FPU_rm));
} }
void fmul_i() void fmul_i()
{ {
/* fmul st(i),st */ /* fmul st(i),st */
reg_mul(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm)); reg_mul(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
PRECISION_ADJUST(&st(FPU_rm));
} }
...@@ -85,9 +77,8 @@ void fsubri() ...@@ -85,9 +77,8 @@ void fsubri()
{ {
/* fsubr st(i),st */ /* fsubr st(i),st */
/* This is the sense of the 80486 manual /* This is the sense of the 80486 manual
reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm)); */ reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word); */
reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm)); reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
PRECISION_ADJUST(&st(FPU_rm));
} }
...@@ -95,25 +86,22 @@ void fsub_i() ...@@ -95,25 +86,22 @@ void fsub_i()
{ {
/* fsub st(i),st */ /* fsub st(i),st */
/* This is the sense of the 80486 manual /* This is the sense of the 80486 manual
reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm)); */ reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word); */
reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm)); reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
PRECISION_ADJUST(&st(FPU_rm));
} }
void fdivri() void fdivri()
{ {
/* fdivr st(i),st */ /* fdivr st(i),st */
reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm)); reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
PRECISION_ADJUST(&st(FPU_rm));
} }
void fdiv_i() void fdiv_i()
{ {
/* fdiv st(i),st */ /* fdiv st(i),st */
reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm)); reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
PRECISION_ADJUST(&st(FPU_rm));
} }
...@@ -121,8 +109,7 @@ void fdiv_i() ...@@ -121,8 +109,7 @@ void fdiv_i()
void faddp_() void faddp_()
{ {
/* faddp st(i),st */ /* faddp st(i),st */
reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm)); reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
PRECISION_ADJUST(&st(FPU_rm));
pop(); pop();
} }
...@@ -130,8 +117,7 @@ void faddp_() ...@@ -130,8 +117,7 @@ void faddp_()
void fmulp_() void fmulp_()
{ {
/* fmulp st(i),st */ /* fmulp st(i),st */
reg_mul(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm)); reg_mul(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
PRECISION_ADJUST(&st(FPU_rm));
pop(); pop();
} }
...@@ -141,9 +127,8 @@ void fsubrp() ...@@ -141,9 +127,8 @@ void fsubrp()
{ {
/* fsubrp st(i),st */ /* fsubrp st(i),st */
/* This is the sense of the 80486 manual /* This is the sense of the 80486 manual
reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm)); */ reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word); */
reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm)); reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
PRECISION_ADJUST(&st(FPU_rm));
pop(); pop();
} }
...@@ -152,9 +137,8 @@ void fsubp_() ...@@ -152,9 +137,8 @@ void fsubp_()
{ {
/* fsubp st(i),st */ /* fsubp st(i),st */
/* This is the sense of the 80486 manual /* This is the sense of the 80486 manual
reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm)); */ reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word); */
reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm)); reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
PRECISION_ADJUST(&st(FPU_rm));
pop(); pop();
} }
...@@ -162,8 +146,7 @@ void fsubp_() ...@@ -162,8 +146,7 @@ void fsubp_()
void fdivrp() void fdivrp()
{ {
/* fdivrp st(i),st */ /* fdivrp st(i),st */
reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm)); reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
PRECISION_ADJUST(&st(FPU_rm));
pop(); pop();
} }
...@@ -171,8 +154,7 @@ void fdivrp() ...@@ -171,8 +154,7 @@ void fdivrp()
void fdivp_() void fdivp_()
{ {
/* fdivp st(i),st */ /* fdivp st(i),st */
reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm)); reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
PRECISION_ADJUST(&st(FPU_rm));
pop(); pop();
} }
...@@ -92,12 +92,17 @@ extern void poly_div16(long long *x); ...@@ -92,12 +92,17 @@ extern void poly_div16(long long *x);
extern void polynomial(unsigned accum[], unsigned x[], extern void polynomial(unsigned accum[], unsigned x[],
unsigned short terms[][4], int n); unsigned short terms[][4], int n);
extern void normalize(FPU_REG *x); extern void normalize(FPU_REG *x);
extern void reg_div(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ); extern void reg_div(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
extern void reg_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ); unsigned int control_w);
extern void reg_u_mul(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ); extern void reg_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
extern void reg_u_div(long long *arg1, long long *arg2, FPU_REG *answ); unsigned int control_w);
extern void reg_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ); extern void reg_u_mul(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
extern void wm_sqrt(FPU_REG *n); unsigned int control_w);
extern void reg_u_div(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
unsigned int control_w);
extern void reg_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
unsigned int control_w);
extern void wm_sqrt(FPU_REG *n, unsigned int control_w);
extern unsigned shrx(void *l, unsigned x); extern unsigned shrx(void *l, unsigned x);
extern unsigned shrxs(void *v, unsigned x); extern unsigned shrxs(void *v, unsigned x);
extern unsigned long div_small(unsigned long long *x, unsigned long y); extern unsigned long div_small(unsigned long long *x, unsigned long y);
......
...@@ -225,36 +225,37 @@ void math_emulate(long arg) ...@@ -225,36 +225,37 @@ void math_emulate(long arg)
switch ( (FPU_modrm >> 3) & 7 ) switch ( (FPU_modrm >> 3) & 7 )
{ {
case 0: /* fadd */ case 0: /* fadd */
reg_add(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr); reg_add(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
control_word);
break; break;
case 1: /* fmul */ case 1: /* fmul */
reg_mul(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr); reg_mul(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
control_word);
break; break;
case 2: /* fcom */ case 2: /* fcom */
compare_st_data(); compare_st_data();
goto no_precision_adjust;
break; break;
case 3: /* fcomp */ case 3: /* fcomp */
compare_st_data(); compare_st_data();
pop(); pop();
goto no_precision_adjust;
break; break;
case 4: /* fsub */ case 4: /* fsub */
reg_sub(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr); reg_sub(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
control_word);
break; break;
case 5: /* fsubr */ case 5: /* fsubr */
reg_sub(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr); reg_sub(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr,
control_word);
break; break;
case 6: /* fdiv */ case 6: /* fdiv */
reg_div(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr); reg_div(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
control_word);
break; break;
case 7: /* fdivr */ case 7: /* fdivr */
reg_div(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr); reg_div(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr,
control_word);
break; break;
} }
PRECISION_ADJUST(FPU_st0_ptr);
no_precision_adjust:
;
} }
else else
stack_underflow(); stack_underflow();
...@@ -338,7 +339,6 @@ void math_emulate(long arg) ...@@ -338,7 +339,6 @@ void math_emulate(long arg)
void __math_abort(struct info * info, unsigned int signal) void __math_abort(struct info * info, unsigned int signal)
{ {
RE_ENTRANT_CHECK_OFF
FPU_EIP = FPU_ORIG_EIP; FPU_EIP = FPU_ORIG_EIP;
send_sig(signal,current,1); send_sig(signal,current,1);
RE_ENTRANT_CHECK_OFF RE_ENTRANT_CHECK_OFF
......
...@@ -68,8 +68,8 @@ extern void poly_tan(FPU_REG *arg, FPU_REG *y_reg); ...@@ -68,8 +68,8 @@ extern void poly_tan(FPU_REG *arg, FPU_REG *y_reg);
extern int round_to_53_bits(FPU_REG *reg); extern int round_to_53_bits(FPU_REG *reg);
extern int round_to_24_bits(FPU_REG *reg); extern int round_to_24_bits(FPU_REG *reg);
/* reg_add_sub.c */ /* reg_add_sub.c */
extern void reg_add(FPU_REG *a, FPU_REG *b, FPU_REG *dest); extern void reg_add(FPU_REG *a, FPU_REG *b, FPU_REG *dest, int control_w);
extern void reg_sub(FPU_REG *a, FPU_REG *b, FPU_REG *dest); extern void reg_sub(FPU_REG *a, FPU_REG *b, FPU_REG *dest, int control_w);
/* reg_compare.c */ /* reg_compare.c */
extern int compare(FPU_REG *b); extern int compare(FPU_REG *b);
extern void compare_st_data(void); extern void compare_st_data(void);
...@@ -102,4 +102,4 @@ extern void frstor(void); ...@@ -102,4 +102,4 @@ extern void frstor(void);
extern char *fstenv(void); extern char *fstenv(void);
extern void fsave(void); extern void fsave(void);
/* reg_mul.c */ /* reg_mul.c */
extern void reg_mul(FPU_REG *a, FPU_REG *b, FPU_REG *dest); extern void reg_mul(FPU_REG *a, FPU_REG *b, FPU_REG *dest, unsigned int control_w);
...@@ -30,7 +30,7 @@ static int trig_arg(FPU_REG *X) ...@@ -30,7 +30,7 @@ static int trig_arg(FPU_REG *X)
control_word |= RC_CHOP; control_word |= RC_CHOP;
reg_move(X, &quot); reg_move(X, &quot);
reg_div(&quot, &CONST_PI2, &quot); reg_div(&quot, &CONST_PI2, &quot, FULL_PRECISION);
reg_move(&quot, &tmp); reg_move(&quot, &tmp);
round_to_int(&tmp); round_to_int(&tmp);
...@@ -40,7 +40,7 @@ static int trig_arg(FPU_REG *X) ...@@ -40,7 +40,7 @@ static int trig_arg(FPU_REG *X)
q = *(long long *)&(tmp.sigl); q = *(long long *)&(tmp.sigl);
normalize(&tmp); normalize(&tmp);
reg_sub(&quot, &tmp, X); reg_sub(&quot, &tmp, X, FULL_PRECISION);
rv = q & 7; rv = q & 7;
control_word = old_cw; control_word = old_cw;
...@@ -107,17 +107,17 @@ static void f2xm1(void) ...@@ -107,17 +107,17 @@ static void f2xm1(void)
/* poly_2xm1(x) requires 0 < x < 1. */ /* poly_2xm1(x) requires 0 < x < 1. */
if ( poly_2xm1(FPU_st0_ptr, &rv) ) if ( poly_2xm1(FPU_st0_ptr, &rv) )
return; /* error */ return; /* error */
reg_mul(&rv, FPU_st0_ptr, FPU_st0_ptr); reg_mul(&rv, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION);
} }
else else
{ {
/* **** Should change poly_2xm1() to at least handle numbers near 0 */ /* **** Should change poly_2xm1() to at least handle numbers near 0 */
/* poly_2xm1(x) doesn't handle negative numbers. */ /* poly_2xm1(x) doesn't handle negative numbers. */
/* So we compute (poly_2xm1(x+1)-1)/2, for -1 < x < 0 */ /* So we compute (poly_2xm1(x+1)-1)/2, for -1 < x < 0 */
reg_add(FPU_st0_ptr, &CONST_1, &tmp); reg_add(FPU_st0_ptr, &CONST_1, &tmp, FULL_PRECISION);
poly_2xm1(&tmp, &rv); poly_2xm1(&tmp, &rv);
reg_mul(&rv, &tmp, &tmp); reg_mul(&rv, &tmp, &tmp, FULL_PRECISION);
reg_sub(&tmp, &CONST_1, FPU_st0_ptr); reg_sub(&tmp, &CONST_1, FPU_st0_ptr, FULL_PRECISION);
FPU_st0_ptr->exp--; FPU_st0_ptr->exp--;
if ( FPU_st0_ptr->exp <= EXP_UNDER ) if ( FPU_st0_ptr->exp <= EXP_UNDER )
arith_underflow(FPU_st0_ptr); arith_underflow(FPU_st0_ptr);
...@@ -155,7 +155,7 @@ static void fptan(void) ...@@ -155,7 +155,7 @@ static void fptan(void)
if ( (q = trig_arg(FPU_st0_ptr)) != -1 ) if ( (q = trig_arg(FPU_st0_ptr)) != -1 )
{ {
if (q & 1) if (q & 1)
reg_sub(&CONST_1, FPU_st0_ptr, FPU_st0_ptr); reg_sub(&CONST_1, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION);
poly_tan(FPU_st0_ptr, FPU_st0_ptr); poly_tan(FPU_st0_ptr, FPU_st0_ptr);
...@@ -286,10 +286,9 @@ static void fsqrt_(void) ...@@ -286,10 +286,9 @@ static void fsqrt_(void)
expon = FPU_st0_ptr->exp - EXP_BIAS; expon = FPU_st0_ptr->exp - EXP_BIAS;
FPU_st0_ptr->exp = EXP_BIAS + (expon & 1); /* make st(0) in [1.0 .. 4.0) */ FPU_st0_ptr->exp = EXP_BIAS + (expon & 1); /* make st(0) in [1.0 .. 4.0) */
wm_sqrt(FPU_st0_ptr); /* Do the computation */ wm_sqrt(FPU_st0_ptr, control_word); /* Do the computation */
FPU_st0_ptr->exp += expon >> 1; FPU_st0_ptr->exp += expon >> 1;
FPU_st0_ptr->tag = TW_Valid;
FPU_st0_ptr->sign = SIGN_POS; FPU_st0_ptr->sign = SIGN_POS;
} }
else if ( FPU_st0_tag == TW_Zero ) else if ( FPU_st0_tag == TW_Zero )
...@@ -303,7 +302,6 @@ static void fsqrt_(void) ...@@ -303,7 +302,6 @@ static void fsqrt_(void)
else else
{ single_arg_error(); return; } { single_arg_error(); return; }
PRECISION_ADJUST(FPU_st0_ptr);
} }
...@@ -338,7 +336,7 @@ static void fsin(void) ...@@ -338,7 +336,7 @@ static void fsin(void)
FPU_REG rv; FPU_REG rv;
if (q & 1) if (q & 1)
reg_sub(&CONST_1, FPU_st0_ptr, FPU_st0_ptr); reg_sub(&CONST_1, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION);
poly_sine(FPU_st0_ptr, &rv); poly_sine(FPU_st0_ptr, &rv);
...@@ -390,7 +388,7 @@ static int f_cos(FPU_REG *arg) ...@@ -390,7 +388,7 @@ static int f_cos(FPU_REG *arg)
FPU_REG rv; FPU_REG rv;
if ( !(q & 1) ) if ( !(q & 1) )
reg_sub(&CONST_1, arg, arg); reg_sub(&CONST_1, arg, arg, FULL_PRECISION);
poly_sine(arg, &rv); poly_sine(arg, &rv);
...@@ -479,15 +477,15 @@ static void fprem_kernel(int round) ...@@ -479,15 +477,15 @@ static void fprem_kernel(int round)
/* This should be the most common case */ /* This should be the most common case */
long long q; long long q;
int c = 0; int c = 0;
reg_div(FPU_st0_ptr, st1_ptr, &tmp); reg_div(FPU_st0_ptr, st1_ptr, &tmp, FULL_PRECISION);
round_to_int(&tmp); /* Fortunately, this can't overflow to 2^64 */ round_to_int(&tmp); /* Fortunately, this can't overflow to 2^64 */
tmp.exp = EXP_BIAS + 63; tmp.exp = EXP_BIAS + 63;
q = *(long long *)&(tmp.sigl); q = *(long long *)&(tmp.sigl);
normalize(&tmp); normalize(&tmp);
reg_mul(st1_ptr, &tmp, &tmp); reg_mul(st1_ptr, &tmp, &tmp, FULL_PRECISION);
reg_sub(FPU_st0_ptr, &tmp, FPU_st0_ptr); reg_sub(FPU_st0_ptr, &tmp, FPU_st0_ptr, FULL_PRECISION);
if (q&4) c |= SW_C3; if (q&4) c |= SW_C3;
if (q&2) c |= SW_C1; if (q&2) c |= SW_C1;
...@@ -500,7 +498,7 @@ static void fprem_kernel(int round) ...@@ -500,7 +498,7 @@ static void fprem_kernel(int round)
/* There is a large exponent difference ( >= 64 ) */ /* There is a large exponent difference ( >= 64 ) */
int N_exp; int N_exp;
reg_div(FPU_st0_ptr, st1_ptr, &tmp); reg_div(FPU_st0_ptr, st1_ptr, &tmp, FULL_PRECISION);
/* N is 'a number between 32 and 63' (p26-113) */ /* N is 'a number between 32 and 63' (p26-113) */
N_exp = (tmp.exp & 31) + 32; N_exp = (tmp.exp & 31) + 32;
tmp.exp = EXP_BIAS + N_exp; tmp.exp = EXP_BIAS + N_exp;
...@@ -511,8 +509,8 @@ static void fprem_kernel(int round) ...@@ -511,8 +509,8 @@ static void fprem_kernel(int round)
tmp.exp = EXP_BIAS + expdif - N_exp; tmp.exp = EXP_BIAS + expdif - N_exp;
reg_mul(st1_ptr, &tmp, &tmp); reg_mul(st1_ptr, &tmp, &tmp, FULL_PRECISION);
reg_sub(FPU_st0_ptr, &tmp, FPU_st0_ptr); reg_sub(FPU_st0_ptr, &tmp, FPU_st0_ptr, FULL_PRECISION);
setcc(SW_C2); setcc(SW_C2);
} }
...@@ -556,7 +554,7 @@ static void fyl2x(void) ...@@ -556,7 +554,7 @@ static void fyl2x(void)
{ {
poly_l2(FPU_st0_ptr, FPU_st0_ptr); poly_l2(FPU_st0_ptr, FPU_st0_ptr);
reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr); reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION);
pop(); FPU_st0_ptr = &st(0); pop(); FPU_st0_ptr = &st(0);
if ( FPU_st0_ptr->exp <= EXP_UNDER ) if ( FPU_st0_ptr->exp <= EXP_UNDER )
{ arith_underflow(FPU_st0_ptr); return; } { arith_underflow(FPU_st0_ptr); return; }
...@@ -667,20 +665,20 @@ static void fpatan(void) ...@@ -667,20 +665,20 @@ static void fpatan(void)
if (compare(st1_ptr) == COMP_A_LT_B) if (compare(st1_ptr) == COMP_A_LT_B)
{ {
quadrant |= 4; quadrant |= 4;
reg_div(FPU_st0_ptr, st1_ptr, &sum); reg_div(FPU_st0_ptr, st1_ptr, &sum, FULL_PRECISION);
} }
else else
reg_div(st1_ptr, FPU_st0_ptr, &sum); reg_div(st1_ptr, FPU_st0_ptr, &sum, FULL_PRECISION);
poly_atan(&sum); poly_atan(&sum);
if (quadrant & 4) if (quadrant & 4)
{ {
reg_sub(&CONST_PI2, &sum, &sum); reg_sub(&CONST_PI2, &sum, &sum, FULL_PRECISION);
} }
if (quadrant & 2) if (quadrant & 2)
{ {
reg_sub(&CONST_PI, &sum, &sum); reg_sub(&CONST_PI, &sum, &sum, FULL_PRECISION);
} }
if (quadrant & 1) if (quadrant & 1)
sum.sign ^= SIGN_POS^SIGN_NEG; sum.sign ^= SIGN_POS^SIGN_NEG;
...@@ -708,7 +706,7 @@ static void fpatan(void) ...@@ -708,7 +706,7 @@ static void fpatan(void)
if ( FPU_st0_ptr->sign == SIGN_POS ) if ( FPU_st0_ptr->sign == SIGN_POS )
{ reg_move(&CONST_PI4, st1_ptr); } { reg_move(&CONST_PI4, st1_ptr); }
else else
reg_add(&CONST_PI4, &CONST_PI2, st1_ptr); reg_add(&CONST_PI4, &CONST_PI2, st1_ptr, FULL_PRECISION);
} }
else else
{ {
...@@ -775,7 +773,7 @@ static void fyl2xp1(void) ...@@ -775,7 +773,7 @@ static void fyl2xp1(void)
arith_invalid(st1_ptr); pop(); return; arith_invalid(st1_ptr); pop(); return;
} }
reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr); reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION);
pop(); pop();
} }
else if ( (FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty) ) else if ( (FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty) )
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
| | | |
| Compute the tan of a FPU_REG, using a polynomial approximation. | | Compute the tan of a FPU_REG, using a polynomial approximation. |
| | | |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | Copyright (C) 1992,1993 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au | | Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| | | |
| | | |
...@@ -12,6 +13,7 @@ ...@@ -12,6 +13,7 @@
#include "exception.h" #include "exception.h"
#include "reg_constant.h" #include "reg_constant.h"
#include "fpu_emu.h" #include "fpu_emu.h"
#include "control_w.h"
#define HIPOWERon 6 /* odd poly, negative terms */ #define HIPOWERon 6 /* odd poly, negative terms */
...@@ -111,8 +113,7 @@ void poly_atan(FPU_REG *arg) ...@@ -111,8 +113,7 @@ void poly_atan(FPU_REG *arg)
denom.sigh |= 0x80000000; /* 1 + arg */ denom.sigh |= 0x80000000; /* 1 + arg */
arg->exp = numerator.exp; arg->exp = numerator.exp;
reg_u_div((long long *)&(numerator.sigl), reg_u_div(&numerator, &denom, arg, FULL_PRECISION);
(long long *)&(denom.sigl), arg);
exponent = arg->exp - EXP_BIAS; exponent = arg->exp - EXP_BIAS;
} }
...@@ -161,7 +162,8 @@ void poly_atan(FPU_REG *arg) ...@@ -161,7 +162,8 @@ void poly_atan(FPU_REG *arg)
reg_move(&pos_poly, &odd_poly); reg_move(&pos_poly, &odd_poly);
poly_add_1(&odd_poly); poly_add_1(&odd_poly);
reg_u_mul(&odd_poly, arg, &odd_poly); /* The complete odd polynomial */ /* The complete odd polynomial */
reg_u_mul(&odd_poly, arg, &odd_poly, FULL_PRECISION);
odd_poly.exp -= EXP_BIAS - 1; odd_poly.exp -= EXP_BIAS - 1;
/* will be a valid positive nr with expon = 0 */ /* will be a valid positive nr with expon = 0 */
...@@ -172,10 +174,10 @@ void poly_atan(FPU_REG *arg) ...@@ -172,10 +174,10 @@ void poly_atan(FPU_REG *arg)
poly_add_1(&even_poly); poly_add_1(&even_poly);
reg_div(&odd_poly, &even_poly, arg); reg_div(&odd_poly, &even_poly, arg, FULL_PRECISION);
if ( recursions ) if ( recursions )
reg_sub(&CONST_PI4, arg, arg); reg_sub(&CONST_PI4, arg, arg, FULL_PRECISION);
} }
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
| | | |
| Compute the base 2 log of a FPU_REG, using a polynomial approximation. | | Compute the base 2 log of a FPU_REG, using a polynomial approximation. |
| | | |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | Copyright (C) 1992,1993 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au | | Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| | | |
| | | |
...@@ -13,6 +14,7 @@ ...@@ -13,6 +14,7 @@
#include "exception.h" #include "exception.h"
#include "reg_constant.h" #include "reg_constant.h"
#include "fpu_emu.h" #include "fpu_emu.h"
#include "control_w.h"
...@@ -60,7 +62,7 @@ void poly_l2(FPU_REG *arg, FPU_REG *result) ...@@ -60,7 +62,7 @@ void poly_l2(FPU_REG *arg, FPU_REG *result)
exponent++; exponent++;
accum.sign = 1; /* sign to negative */ accum.sign = 1; /* sign to negative */
num.exp = EXP_BIAS; /* needed to prevent errors in div routine */ num.exp = EXP_BIAS; /* needed to prevent errors in div routine */
reg_u_div((long long *)&(CONST_1.sigl), (long long *)&(arg->sigl), &num); reg_u_div(&CONST_1, arg, &num, FULL_PRECISION);
} }
else else
{ {
...@@ -79,7 +81,7 @@ void poly_l2(FPU_REG *arg, FPU_REG *result) ...@@ -79,7 +81,7 @@ void poly_l2(FPU_REG *arg, FPU_REG *result)
poly_div4((long long *)&(denom.sigl)); poly_div4((long long *)&(denom.sigl));
denom.sigh += 0x80000000; /* set the msb */ denom.sigh += 0x80000000; /* set the msb */
Xx.exp = EXP_BIAS; /* needed to prevent errors in div routine */ Xx.exp = EXP_BIAS; /* needed to prevent errors in div routine */
reg_u_div((long long *)&num.sigl, (long long *)&(denom.sigl), &Xx); reg_u_div(&num, &denom, &Xx, FULL_PRECISION);
zero = !(Xx.sigh | Xx.sigl); zero = !(Xx.sigh | Xx.sigl);
...@@ -122,7 +124,7 @@ void poly_l2(FPU_REG *arg, FPU_REG *result) ...@@ -122,7 +124,7 @@ void poly_l2(FPU_REG *arg, FPU_REG *result)
/* Use 1-1/(1-x) = x/(1-x) */ /* Use 1-1/(1-x) = x/(1-x) */
*((long long *)&num.sigl) = - *((long long *)&(arg->sigl)); *((long long *)&num.sigl) = - *((long long *)&(arg->sigl));
normalize(&num); normalize(&num);
reg_div(&num, arg, &num); reg_div(&num, arg, &num, FULL_PRECISION);
} }
else else
{ {
...@@ -133,12 +135,12 @@ void poly_l2(FPU_REG *arg, FPU_REG *result) ...@@ -133,12 +135,12 @@ void poly_l2(FPU_REG *arg, FPU_REG *result)
denom.sign = SIGN_POS; /* set the sign to positive */ denom.sign = SIGN_POS; /* set the sign to positive */
denom.exp = EXP_BIAS; denom.exp = EXP_BIAS;
reg_div(&num, &denom, &lXx); reg_div(&num, &denom, &lXx, FULL_PRECISION);
reg_u_mul(&lXx, &accum, &accum); reg_u_mul(&lXx, &accum, &accum, FULL_PRECISION);
accum.exp += - EXP_BIAS + 1; accum.exp += - EXP_BIAS + 1;
reg_u_add(&lXx, &accum, result); reg_u_add(&lXx, &accum, result, FULL_PRECISION);
normalize(result); normalize(result);
} }
...@@ -230,15 +232,15 @@ int poly_l2p1(FPU_REG *arg, FPU_REG *result) ...@@ -230,15 +232,15 @@ int poly_l2p1(FPU_REG *arg, FPU_REG *result)
sign = arg->sign; sign = arg->sign;
reg_add(arg, &CONST_1, &arg_pl1); reg_add(arg, &CONST_1, &arg_pl1, FULL_PRECISION);
if ( (arg_pl1.sign) | (arg_pl1.tag) ) if ( (arg_pl1.sign) | (arg_pl1.tag) )
{ /* We need a valid positive number! */ { /* We need a valid positive number! */
return 1; return 1;
} }
reg_add(&CONST_1, &arg_pl1, &denom); reg_add(&CONST_1, &arg_pl1, &denom, FULL_PRECISION);
reg_div(arg, &denom, &local_arg); reg_div(arg, &denom, &local_arg, FULL_PRECISION);
local_arg.sign = 0; /* Make the sign positive */ local_arg.sign = 0; /* Make the sign positive */
/* Now we need to check that |local_arg| is less than /* Now we need to check that |local_arg| is less than
...@@ -273,10 +275,10 @@ int poly_l2p1(FPU_REG *arg, FPU_REG *result) ...@@ -273,10 +275,10 @@ int poly_l2p1(FPU_REG *arg, FPU_REG *result)
accum.exp = EXP_BIAS - 1; accum.exp = EXP_BIAS - 1;
normalize(&accum); normalize(&accum);
reg_u_mul(&local_arg, &accum, &accum); reg_u_mul(&local_arg, &accum, &accum, FULL_PRECISION);
accum.exp -= EXP_BIAS - 1; accum.exp -= EXP_BIAS - 1;
reg_u_add(&local_arg, &accum, result); reg_u_add(&local_arg, &accum, result, FULL_PRECISION);
/* Multiply the result by 2 */ /* Multiply the result by 2 */
result->exp++; result->exp++;
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
| | | |
| Computation of an approximation of the sin function by a polynomial | | Computation of an approximation of the sin function by a polynomial |
| | | |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | Copyright (C) 1992,1993 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au | | Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| | | |
| | | |
...@@ -13,6 +14,7 @@ ...@@ -13,6 +14,7 @@
#include "exception.h" #include "exception.h"
#include "reg_constant.h" #include "reg_constant.h"
#include "fpu_emu.h" #include "fpu_emu.h"
#include "control_w.h"
#define HIPOWER 5 #define HIPOWER 5
...@@ -117,8 +119,8 @@ void poly_sine(FPU_REG *arg, FPU_REG *result) ...@@ -117,8 +119,8 @@ void poly_sine(FPU_REG *arg, FPU_REG *result)
normalize(result); normalize(result);
reg_mul(result, arg, result); reg_mul(result, arg, result, FULL_PRECISION);
reg_u_add(result, arg, result); reg_u_add(result, arg, result, FULL_PRECISION);
/* A small overflow may be possible... but an illegal result. */ /* A small overflow may be possible... but an illegal result. */
if ( result->exp >= EXP_BIAS ) if ( result->exp >= EXP_BIAS )
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
| | | |
| Compute the tan of a FPU_REG, using a polynomial approximation. | | Compute the tan of a FPU_REG, using a polynomial approximation. |
| | | |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | Copyright (C) 1992,1993 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au | | Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| | | |
| | | |
...@@ -12,6 +13,7 @@ ...@@ -12,6 +13,7 @@
#include "exception.h" #include "exception.h"
#include "reg_constant.h" #include "reg_constant.h"
#include "fpu_emu.h" #include "fpu_emu.h"
#include "control_w.h"
#define HIPOWERop 3 /* odd poly, positive terms */ #define HIPOWERop 3 /* odd poly, positive terms */
...@@ -131,8 +133,8 @@ void poly_tan(FPU_REG *arg, FPU_REG *y_reg) ...@@ -131,8 +133,8 @@ void poly_tan(FPU_REG *arg, FPU_REG *y_reg)
reg_move(&pos_poly, &odd_poly); reg_move(&pos_poly, &odd_poly);
normalize(&odd_poly); normalize(&odd_poly);
reg_mul(&odd_poly, arg, &odd_poly); reg_mul(&odd_poly, arg, &odd_poly, FULL_PRECISION);
reg_u_add(&odd_poly, arg, &odd_poly); /* This is just the odd polynomial */ reg_u_add(&odd_poly, arg, &odd_poly, FULL_PRECISION); /* This is just the odd polynomial */
/* will be a valid positive nr with expon = 0 */ /* will be a valid positive nr with expon = 0 */
...@@ -166,14 +168,14 @@ void poly_tan(FPU_REG *arg, FPU_REG *y_reg) ...@@ -166,14 +168,14 @@ void poly_tan(FPU_REG *arg, FPU_REG *y_reg)
reg_move(&neg_poly, &even_poly); reg_move(&neg_poly, &even_poly);
normalize(&even_poly); normalize(&even_poly);
reg_mul(&even_poly, &argSq, &even_poly); reg_mul(&even_poly, &argSq, &even_poly, FULL_PRECISION);
reg_add(&even_poly, &argSq, &even_poly); reg_add(&even_poly, &argSq, &even_poly, FULL_PRECISION);
reg_sub(&CONST_1, &even_poly, &even_poly); /* This is just the even polynomial */ reg_sub(&CONST_1, &even_poly, &even_poly, FULL_PRECISION); /* This is just the even polynomial */
/* Now ready to copy the results */ /* Now ready to copy the results */
if ( invert ) if ( invert )
{ reg_div(&even_poly, &odd_poly, y_reg); } { reg_div(&even_poly, &odd_poly, y_reg, FULL_PRECISION); }
else else
{ reg_div(&odd_poly, &even_poly, y_reg); } { reg_div(&odd_poly, &even_poly, y_reg, FULL_PRECISION); }
} }
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
| | | |
| Fixed point arithmetic polynomial evaluation. | | Fixed point arithmetic polynomial evaluation. |
| | | |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | Copyright (C) 1992,1993 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au | | Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| | | |
| Call from C as: | | Call from C as: |
...@@ -54,9 +55,9 @@ _polynomial: ...@@ -54,9 +55,9 @@ _polynomial:
movl %eax,-28(%ebp) movl %eax,-28(%ebp)
subl TERM_SIZE,%ecx subl TERM_SIZE,%ecx
js xL_accum_done js L_accum_done
xL_accum_loop: L_accum_loop:
xor %eax,%eax xor %eax,%eax
movl %eax,-4(%ebp) movl %eax,-4(%ebp)
movl %eax,-8(%ebp) movl %eax,-8(%ebp)
...@@ -107,27 +108,27 @@ xL_accum_loop: ...@@ -107,27 +108,27 @@ xL_accum_loop:
movl %eax,-28(%ebp) movl %eax,-28(%ebp)
#else #else
testb $128,-25(%ebp) testb $128,-25(%ebp)
je xL_no_poly_round je L_no_poly_round
addl $1,-24(%ebp) addl $1,-24(%ebp)
adcl $0,-20(%ebp) adcl $0,-20(%ebp)
xL_no_poly_round: L_no_poly_round:
#endif EXTRA_PRECISE #endif EXTRA_PRECISE
subl TERM_SIZE,%ecx subl TERM_SIZE,%ecx
jns xL_accum_loop jns L_accum_loop
xL_accum_done: L_accum_done:
#ifdef EXTRA_PRECISE #ifdef EXTRA_PRECISE
/* And round the result */ /* And round the result */
testb $128,-25(%ebp) testb $128,-25(%ebp)
je xL_poly_done je L_poly_done
addl $1,-24(%ebp) addl $1,-24(%ebp)
adcl $0,-20(%ebp) adcl $0,-20(%ebp)
#endif EXTRA_PRECISE #endif EXTRA_PRECISE
xL_poly_done: L_poly_done:
movl -24(%ebp),%eax movl -24(%ebp),%eax
movl %eax,(%esi) movl %eax,(%esi)
movl -20(%ebp),%eax movl -20(%ebp),%eax
......
/*---------------------------------------------------------------------------+
| precision.c |
| |
| The functions which adjust the precision of a result. |
| |
| Copyright (C) 1993 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| |
| |
+---------------------------------------------------------------------------*/
#include <asm/segment.h>
#include "fpu_system.h"
#include "exception.h"
#include "reg_constant.h"
#include "fpu_emu.h"
#include "control_w.h"
/* Round the result to 53 bits */
int round_to_53_bits(FPU_REG *reg)
{
if (reg->tag == TW_Valid)
{
unsigned long increment = 0; /* avoid gcc warnings */
switch (control_word & CW_RC)
{
case RC_RND:
/* Rounding can get a little messy.. */
increment = ((reg->sigl & 0x7ff) > 0x400) | /* nearest */
((reg->sigl & 0xc00) == 0xc00); /* odd -> even */
break;
case RC_DOWN: /* towards -infinity */
increment = (reg->sign == SIGN_POS) ? 0 : reg->sigl & 0x7ff;
break;
case RC_UP: /* towards +infinity */
increment = (reg->sign == SIGN_POS) ? reg->sigl & 0x7ff : 0;
break;
case RC_CHOP:
increment = 0;
break;
}
/* Truncate the mantissa */
reg->sigl &= 0xfffff800;
if ( increment )
{
if ( reg->sigl >= 0xfffff800 )
{
/* the sigl part overflows */
if ( reg->sigh == 0xffffffff )
{
/* The sigh part overflows */
reg->sigh = 0x80000000;
reg->exp++;
if (reg->exp >= EXP_OVER)
{ arith_overflow(reg); return 1; }
}
else
{
reg->sigh ++;
}
reg->sigl = 0x00000000;
}
else
{
/* We only need to increment sigl */
reg->sigl += 0x00000800;
}
}
}
return 0;
}
/* Round the result to 24 bits */
int round_to_24_bits(FPU_REG *reg)
{
if (reg->tag == TW_Valid)
{
unsigned long increment = 0; /* avoid gcc warnings */
unsigned long sigh = reg->sigh;
unsigned long sigl = reg->sigl;
switch (control_word & CW_RC)
{
case RC_RND:
increment = ((sigh & 0xff) > 0x80) /* more than half */
|| (((sigh & 0xff) == 0x80) && sigl) /* more than half */
|| ((sigh & 0x180) == 0x180); /* round to even */
break;
case RC_DOWN: /* towards -infinity */
increment = (reg->sign == SIGN_POS) ? 0 : (sigl | (sigh & 0xff));
break;
case RC_UP: /* towards +infinity */
increment = (reg->sign == SIGN_POS) ? (sigl | (sigh & 0xff)) : 0;
break;
case RC_CHOP:
increment = 0;
break;
}
/* Truncate the mantissa */
reg->sigl = 0;
if (increment)
{
if ( sigh >= 0xffffff00 )
{
/* The sigh part overflows */
reg->sigh = 0x80000000;
reg->exp++;
if (reg->exp >= EXP_OVER)
{ arith_overflow(reg); return 1; }
}
else
{
reg->sigh &= 0xffffff00;
reg->sigh += 0x100;
}
}
}
return 0;
}
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include "fpu_system.h" #include "fpu_system.h"
void reg_add(FPU_REG *a, FPU_REG *b, FPU_REG *dest) void reg_add(FPU_REG *a, FPU_REG *b, FPU_REG *dest, int control_w)
{ {
int diff; int diff;
...@@ -32,7 +32,7 @@ void reg_add(FPU_REG *a, FPU_REG *b, FPU_REG *dest) ...@@ -32,7 +32,7 @@ void reg_add(FPU_REG *a, FPU_REG *b, FPU_REG *dest)
if (!(a->sign ^ b->sign)) if (!(a->sign ^ b->sign))
{ {
/* signs are the same */ /* signs are the same */
reg_u_add(a, b, dest); reg_u_add(a, b, dest, control_w);
dest->sign = a->sign; dest->sign = a->sign;
return; return;
} }
...@@ -52,19 +52,19 @@ void reg_add(FPU_REG *a, FPU_REG *b, FPU_REG *dest) ...@@ -52,19 +52,19 @@ void reg_add(FPU_REG *a, FPU_REG *b, FPU_REG *dest)
if (diff > 0) if (diff > 0)
{ {
reg_u_sub(a, b, dest); reg_u_sub(a, b, dest, control_w);
dest->sign = a->sign; dest->sign = a->sign;
} }
else if ( diff == 0 ) else if ( diff == 0 )
{ {
reg_move(&CONST_Z, dest); reg_move(&CONST_Z, dest);
/* sign depends upon rounding mode */ /* sign depends upon rounding mode */
dest->sign = ((control_word & CW_RC) != RC_DOWN) dest->sign = ((control_w & CW_RC) != RC_DOWN)
? SIGN_POS : SIGN_NEG; ? SIGN_POS : SIGN_NEG;
} }
else else
{ {
reg_u_sub(b, a, dest); reg_u_sub(b, a, dest, control_w);
dest->sign = b->sign; dest->sign = b->sign;
} }
return; return;
...@@ -84,7 +84,7 @@ void reg_add(FPU_REG *a, FPU_REG *b, FPU_REG *dest) ...@@ -84,7 +84,7 @@ void reg_add(FPU_REG *a, FPU_REG *b, FPU_REG *dest)
{ {
/* Signs are different. */ /* Signs are different. */
/* Sign of answer depends upon rounding mode. */ /* Sign of answer depends upon rounding mode. */
dest->sign = ((control_word & CW_RC) != RC_DOWN) dest->sign = ((control_w & CW_RC) != RC_DOWN)
? SIGN_POS : SIGN_NEG; ? SIGN_POS : SIGN_NEG;
} }
} }
...@@ -114,7 +114,7 @@ void reg_add(FPU_REG *a, FPU_REG *b, FPU_REG *dest) ...@@ -114,7 +114,7 @@ void reg_add(FPU_REG *a, FPU_REG *b, FPU_REG *dest)
/* Subtract b from a. (a-b) -> dest */ /* Subtract b from a. (a-b) -> dest */
void reg_sub(FPU_REG *a, FPU_REG *b, FPU_REG *dest) void reg_sub(FPU_REG *a, FPU_REG *b, FPU_REG *dest, int control_w)
{ {
int diff; int diff;
...@@ -139,28 +139,28 @@ void reg_sub(FPU_REG *a, FPU_REG *b, FPU_REG *dest) ...@@ -139,28 +139,28 @@ void reg_sub(FPU_REG *a, FPU_REG *b, FPU_REG *dest)
case 3: /* N - N */ case 3: /* N - N */
if (diff > 0) if (diff > 0)
{ {
reg_u_sub(a, b, dest); reg_u_sub(a, b, dest, control_w);
dest->sign = a->sign; dest->sign = a->sign;
} }
else if ( diff == 0 ) else if ( diff == 0 )
{ {
reg_move(&CONST_Z, dest); reg_move(&CONST_Z, dest);
/* sign depends upon rounding mode */ /* sign depends upon rounding mode */
dest->sign = ((control_word & CW_RC) != RC_DOWN) dest->sign = ((control_w & CW_RC) != RC_DOWN)
? SIGN_POS : SIGN_NEG; ? SIGN_POS : SIGN_NEG;
} }
else else
{ {
reg_u_sub(b, a, dest); reg_u_sub(b, a, dest, control_w);
dest->sign = a->sign ^ SIGN_POS^SIGN_NEG; dest->sign = a->sign ^ SIGN_POS^SIGN_NEG;
} }
return; return;
case 1: /* P - N */ case 1: /* P - N */
reg_u_add(a, b, dest); reg_u_add(a, b, dest, control_w);
dest->sign = SIGN_POS; dest->sign = SIGN_POS;
return; return;
case 2: /* N - P */ case 2: /* N - P */
reg_u_add(a, b, dest); reg_u_add(a, b, dest, control_w);
dest->sign = SIGN_NEG; dest->sign = SIGN_NEG;
return; return;
} }
...@@ -179,7 +179,7 @@ void reg_sub(FPU_REG *a, FPU_REG *b, FPU_REG *dest) ...@@ -179,7 +179,7 @@ void reg_sub(FPU_REG *a, FPU_REG *b, FPU_REG *dest)
if (same_signs) if (same_signs)
{ {
/* Sign depends upon rounding mode */ /* Sign depends upon rounding mode */
dest->sign = ((control_word & CW_RC) != RC_DOWN) dest->sign = ((control_w & CW_RC) != RC_DOWN)
? SIGN_POS : SIGN_NEG; ? SIGN_POS : SIGN_NEG;
} }
} }
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
| | | |
| All of the constant FPU_REGs | | All of the constant FPU_REGs |
| | | |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | Copyright (C) 1992,1993 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au | | Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| | | |
| | | |
......
...@@ -4,11 +4,13 @@ ...@@ -4,11 +4,13 @@
| | | |
| Divide one FPU_REG by another and put the result in a destination FPU_REG.| | Divide one FPU_REG by another and put the result in a destination FPU_REG.|
| | | |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | Copyright (C) 1992,1993 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au | | Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| | | |
| Call from C as: | | Call from C as: |
| void reg_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest) | | void reg_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest, |
| unsigned int control_word) |
| | | |
+---------------------------------------------------------------------------*/ +---------------------------------------------------------------------------*/
...@@ -34,7 +36,7 @@ _reg_div: ...@@ -34,7 +36,7 @@ _reg_div:
movb TAG(%esi),%al movb TAG(%esi),%al
orb TAG(%ebx),%al orb TAG(%ebx),%al
jne xL_div_special // Not (both numbers TW_Valid) jne L_div_special // Not (both numbers TW_Valid)
// Both arguments are TW_Valid // Both arguments are TW_Valid
...@@ -50,72 +52,72 @@ _reg_div: ...@@ -50,72 +52,72 @@ _reg_div:
cmpb %cl,SIGN(%ebx) cmpb %cl,SIGN(%ebx)
setne (%edi) // Set the sign, requires SIGN_NEG=1, SIGN_POS=0 setne (%edi) // Set the sign, requires SIGN_NEG=1, SIGN_POS=0
add $SIGL_OFFSET,%ebx // add $SIGL_OFFSET,%ebx
add $SIGL_OFFSET,%esi // add $SIGL_OFFSET,%esi
jmp _divide_kernel jmp _divide_kernel
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
xL_div_special: L_div_special:
cmpb TW_NaN,TAG(%esi) // A NaN with anything to give NaN cmpb TW_NaN,TAG(%esi) // A NaN with anything to give NaN
je xL_arg1_NaN je L_arg1_NaN
cmpb TW_NaN,TAG(%ebx) // A NaN with anything to give NaN cmpb TW_NaN,TAG(%ebx) // A NaN with anything to give NaN
jne xL_no_NaN_arg jne L_no_NaN_arg
// Operations on NaNs // Operations on NaNs
xL_arg1_NaN: L_arg1_NaN:
xL_arg2_NaN: L_arg2_NaN:
pushl %edi pushl %edi
pushl %ebx pushl %ebx
pushl %esi pushl %esi
call _real_2op_NaN call _real_2op_NaN
jmp xL78 jmp LDiv_exit
// Invalid operations // Invalid operations
xL_zero_zero: L_zero_zero:
xL_inf_inf: L_inf_inf:
pushl %esi pushl %esi
call _arith_invalid call _arith_invalid
jmp xL78 jmp LDiv_exit
xL_no_NaN_arg: L_no_NaN_arg:
cmpb TW_Infinity,TAG(%esi) cmpb TW_Infinity,TAG(%esi)
jne xL_arg1_not_inf jne L_arg1_not_inf
cmpb TW_Infinity,TAG(%ebx) cmpb TW_Infinity,TAG(%ebx)
je xL_inf_inf // invalid operation je L_inf_inf // invalid operation
// Note that p16-9 says that infinity/0 returns infinity // Note that p16-9 says that infinity/0 returns infinity
jmp xL_copy_arg1 // Answer is Inf jmp L_copy_arg1 // Answer is Inf
xL_arg1_not_inf: L_arg1_not_inf:
cmpb TW_Zero,TAG(%ebx) // Priority to div-by-zero error cmpb TW_Zero,TAG(%ebx) // Priority to div-by-zero error
jne xL_arg2_not_zero jne L_arg2_not_zero
cmpb TW_Zero,TAG(%esi) cmpb TW_Zero,TAG(%esi)
je xL_zero_zero // invalid operation je L_zero_zero // invalid operation
// Division by zero error // Division by zero error
pushl %esi pushl %esi
movb SIGN(%esi),%al movb SIGN(%esi),%al
xorb SIGN(%ebx),%al xorb SIGN(%ebx),%al
pushl %eax // lower 8 bits have the sign pushl %eax // lower 8 bits have the sign
call _divide_by_zero call _divide_by_zero
jmp xL78 jmp LDiv_exit
xL_arg2_not_zero: L_arg2_not_zero:
cmpb TW_Infinity,TAG(%ebx) cmpb TW_Infinity,TAG(%ebx)
jne xL_arg2_not_inf jne L_arg2_not_inf
jmp xL_return_zero // Answer is zero jmp L_return_zero // Answer is zero
xL_arg2_not_inf: L_arg2_not_inf:
cmpb TW_Zero,TAG(%esi) cmpb TW_Zero,TAG(%esi)
jne xL_unknown_tags jne L_unknown_tags
xL_copy_arg1: L_copy_arg1:
movb TAG(%esi),%ax movb TAG(%esi),%ax
movb %ax,TAG(%edi) movb %ax,TAG(%edi)
movl EXP(%esi),%eax movl EXP(%esi),%eax
...@@ -127,24 +129,24 @@ xL_copy_arg1: ...@@ -127,24 +129,24 @@ xL_copy_arg1:
movb SIGN(%esi),%cl movb SIGN(%esi),%cl
cmpb %cl,SIGN(%ebx) cmpb %cl,SIGN(%ebx)
jne xL76 jne LDiv_negative_result
movb SIGN_POS,SIGN(%edi) movb SIGN_POS,SIGN(%edi)
jmp xL78 jmp LDiv_exit
xL71: LDiv_set_result_sign:
movb SIGN(%esi),%cl movb SIGN(%esi),%cl
cmpb %cl,SIGN(%edi) cmpb %cl,SIGN(%edi)
jne xL76 jne LDiv_negative_result
movb SIGN_POS,SIGN(%ebx) movb SIGN_POS,SIGN(%ebx)
jmp xL78 jmp LDiv_exit
.align 2,0x90 .align 2,0x90
xL76: LDiv_negative_result:
movb SIGN_NEG,SIGN(%edi) movb SIGN_NEG,SIGN(%edi)
xL78: LDiv_exit:
leal -12(%ebp),%esp leal -12(%ebp),%esp
popl %ebx popl %ebx
...@@ -154,11 +156,11 @@ xL78: ...@@ -154,11 +156,11 @@ xL78:
ret ret
xL_return_zero: L_return_zero:
movb TW_Zero,TAG(%edi) movb TW_Zero,TAG(%edi)
jmp xL71 jmp LDiv_set_result_sign
xL_unknown_tags: L_unknown_tags:
push EX_INTERNAL | 0x208 push EX_INTERNAL | 0x208
call EXCEPTION call EXCEPTION
...@@ -169,4 +171,4 @@ xL_unknown_tags: ...@@ -169,4 +171,4 @@ xL_unknown_tags:
movl %eax,SIGL(%edi) movl %eax,SIGL(%edi)
movl _CONST_QNaN+8,%eax movl _CONST_QNaN+8,%eax
movl %eax,SIGH(%edi) movl %eax,SIGH(%edi)
jmp xL78 jmp LDiv_exit
...@@ -503,22 +503,73 @@ int reg_store_double(void) ...@@ -503,22 +503,73 @@ int reg_store_double(void)
double *dfloat = (double *)FPU_data_address; double *dfloat = (double *)FPU_data_address;
unsigned long l[2]; unsigned long l[2];
if (FPU_st0_tag == TW_Valid) if (FPU_st0_tag == TW_Valid)
{ {
int exp; int exp;
FPU_REG tmp; FPU_REG tmp;
reg_move(FPU_st0_ptr, &tmp); reg_move(FPU_st0_ptr, &tmp);
if (round_to_53_bits(&tmp)) goto overflow;
if ( tmp.sigl & 0x000007ff )
{
unsigned long increment = 0; /* avoid gcc warnings */
switch (control_word & CW_RC)
{
case RC_RND:
/* Rounding can get a little messy.. */
increment = ((tmp.sigl & 0x7ff) > 0x400) | /* nearest */
((tmp.sigl & 0xc00) == 0xc00); /* odd -> even */
break;
case RC_DOWN: /* towards -infinity */
increment = (tmp.sign == SIGN_POS) ? 0 : tmp.sigl & 0x7ff;
break;
case RC_UP: /* towards +infinity */
increment = (tmp.sign == SIGN_POS) ? tmp.sigl & 0x7ff : 0;
break;
case RC_CHOP:
increment = 0;
break;
}
/* Truncate the mantissa */
tmp.sigl &= 0xfffff800;
if ( increment )
{
if ( tmp.sigl >= 0xfffff800 )
{
/* the sigl part overflows */
if ( tmp.sigh == 0xffffffff )
{
/* The sigh part overflows */
tmp.sigh = 0x80000000;
tmp.exp++;
if (tmp.exp >= EXP_OVER)
goto overflow;
}
else
{
tmp.sigh ++;
}
tmp.sigl = 0x00000000;
}
else
{
/* We only need to increment sigl */
tmp.sigl += 0x00000800;
}
}
}
l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21); l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
l[1] = ((tmp.sigh >> 11) & 0xfffff); l[1] = ((tmp.sigh >> 11) & 0xfffff);
exp = tmp.exp - EXP_BIAS; exp = tmp.exp - EXP_BIAS;
if ( exp > DOUBLE_Emax ) if ( exp > DOUBLE_Emax )
{ {
EXCEPTION(EX_Overflow);
overflow: overflow:
EXCEPTION(EX_Overflow);
/* This is a special case: see sec 16.2.5.1 of the 80486 book */ /* This is a special case: see sec 16.2.5.1 of the 80486 book */
if ( control_word & EX_Overflow ) if ( control_word & EX_Overflow )
{ {
...@@ -635,14 +686,61 @@ int reg_store_single(void) ...@@ -635,14 +686,61 @@ int reg_store_single(void)
FPU_REG tmp; FPU_REG tmp;
reg_move(FPU_st0_ptr, &tmp); reg_move(FPU_st0_ptr, &tmp);
if (round_to_24_bits(&tmp)) goto overflow;
if ( tmp.sigl | (tmp.sigh & 0x000000ff) )
{
unsigned long increment = 0; /* avoid gcc warnings */
unsigned long sigh = tmp.sigh;
unsigned long sigl = tmp.sigl;
switch (control_word & CW_RC)
{
case RC_RND:
increment = ((sigh & 0xff) > 0x80) /* more than half */
|| (((sigh & 0xff) == 0x80) && sigl) /* more than half */
|| ((sigh & 0x180) == 0x180); /* round to even */
break;
case RC_DOWN: /* towards -infinity */
increment = (tmp.sign == SIGN_POS) ? 0 : (sigl | (sigh & 0xff));
break;
case RC_UP: /* towards +infinity */
increment = (tmp.sign == SIGN_POS) ? (sigl | (sigh & 0xff)) : 0;
break;
case RC_CHOP:
increment = 0;
break;
}
/* Truncate part of the mantissa */
tmp.sigl = 0;
if (increment)
{
if ( sigh >= 0xffffff00 )
{
/* The sigh part overflows */
tmp.sigh = 0x80000000;
tmp.exp++;
if (tmp.exp >= EXP_OVER)
goto overflow;
}
else
{
tmp.sigh &= 0xffffff00;
tmp.sigh += 0x100;
}
}
else
tmp.sigh &= 0xffffff00; /* Finish the truncation */
}
templ = (tmp.sigh >> 8) & 0x007fffff; templ = (tmp.sigh >> 8) & 0x007fffff;
exp = tmp.exp - EXP_BIAS; exp = tmp.exp - EXP_BIAS;
if ( exp > SINGLE_Emax ) if ( exp > SINGLE_Emax )
{ {
EXCEPTION(EX_Overflow);
overflow: overflow:
EXCEPTION(EX_Overflow);
/* This is a special case: see sec 16.2.5.1 of the 80486 book */ /* This is a special case: see sec 16.2.5.1 of the 80486 book */
if ( control_word & EX_Overflow ) if ( control_word & EX_Overflow )
{ {
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
| | | |
| Multiply one FPU_REG by another, put the result in a destination FPU_REG. | | Multiply one FPU_REG by another, put the result in a destination FPU_REG. |
| | | |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | Copyright (C) 1992,1993 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au | | Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| | | |
| | | |
...@@ -16,18 +17,19 @@ ...@@ -16,18 +17,19 @@
#include "exception.h" #include "exception.h"
#include "reg_constant.h" #include "reg_constant.h"
#include "fpu_emu.h" #include "fpu_emu.h"
#include "fpu_system.h"
/* This routine must be called with non-empty registers */ /* This routine must be called with non-empty source registers */
void reg_mul(FPU_REG *a, FPU_REG *b, FPU_REG *dest) void reg_mul(FPU_REG *a, FPU_REG *b, FPU_REG *dest, unsigned int control_w)
{ {
if (!(a->tag | b->tag)) if (!(a->tag | b->tag))
{ {
/* This should be the most common case */ /* This should be the most common case */
reg_u_mul(a, b, dest);
dest->exp += - EXP_BIAS + 1;
dest->sign = (a->sign ^ b->sign); dest->sign = (a->sign ^ b->sign);
dest->tag = TW_Valid; reg_u_mul(a, b, dest, control_w);
dest->exp += - EXP_BIAS + 1;
/* dest->tag = TW_Valid; ****** */
if ( dest->exp <= EXP_UNDER ) if ( dest->exp <= EXP_UNDER )
{ arith_underflow(FPU_st0_ptr); } { arith_underflow(FPU_st0_ptr); }
else if ( dest->exp >= EXP_OVER ) else if ( dest->exp >= EXP_OVER )
......
.file "reg_round.S"
/*---------------------------------------------------------------------------+
| reg_round.S |
| |
| Rounding/truncation/etc for FPU basic arithmetic functions. |
| |
| Copyright (C) 1993 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| |
| Not callable from C. |
| Must be entered by a jmp intruction. |
| |
+---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------+
| Two entry points. |
| |
| Needed by both entry points: |
| %eax:%ebx 64 bit significand |
| %edx 32 bit extension of the significand |
| %edi pointer to an FPU_REG for the result to be stored |
| stack calling function must have set up a C stack frame and |
| pushed %esi, %edi, and %ebx |
| |
| Needed just for the FPU_round_sqrt entry point: |
| %cx A control word in the same format as the FPU control word. |
| Otherwise, PARAM4 must give such a value. |
| |
| |
| The significand and its extension are assumed to be exact in the |
| following sense: |
| If the significand by itself is the exact result then the significand |
| extension (%edx) must contain 0, otherwise the significand extension |
| must be non-zero. |
| If the significand extension is non-zero then the significand is |
| smaller than the magnitude of the correct exact result by an amount |
| greater than zero and less than one ls bit of the significand. |
| The significand extension is only required to have three possible |
| non-zero values: |
| less than 0x80000000 <=> the significand is less than 1/2 an ls |
| bit smaller than the magnitude of the |
| true exact result. |
| exactly 0x80000000 <=> the significand is exactly 1/2 an ls bit |
| smaller than the magnitude of the true |
| exact result. |
| greater than 0x80000000 <=> the significand is more than 1/2 an ls |
| bit smaller than the magnitude of the |
| true exact result. |
| |
+---------------------------------------------------------------------------*/
#include "fpu_asm.h"
#include "fpu_emu.h"
#include "exception.h"
#include "control_w.h"
.text
.align 2,144
.globl FPU_round
.globl FPU_round_sqrt
FPU_round:
/* Round the result */
movl PARAM4,%ecx
FPU_round_sqrt: // entry point from wm_sqrt.S
movl %ecx,%esi
andl CW_PC,%ecx
cmpl PR_64_BITS,%ecx
je LRound_To_64
cmpl PR_53_BITS,%ecx
je LRound_To_53
cmpl PR_24_BITS,%ecx
je LRound_To_24
#ifdef PARANOID
jmp L_bugged // There is no bug, just a bad control word
#endif PARANOID
LRound_To_24:
movl %esi,%ecx
andl CW_RC,%ecx
cmpl RC_RND,%ecx
je LRound_nearest_24
cmpl RC_CHOP,%ecx
je LTruncate_24
cmpl RC_UP,%ecx // Towards +infinity
je LUp_24
cmpl RC_DOWN,%ecx // Towards -infinity
je LDown_24
#ifdef PARANOID
jmp L_bugged
#endif PARANOID
LUp_24:
cmpb SIGN_POS,SIGN(%edi)
je LUp_24_pos
movl %eax,%ecx
andl $0x000000ff,%ecx
orl %ebx,%ecx
orl %edx,%ecx
jnz LTruncate_24
jmp L_store
LUp_24_pos:
movl %eax,%ecx
andl $0x000000ff,%ecx
orl %ebx,%ecx
orl %edx,%ecx
jnz LDo_24_round_up
jmp L_store
LDown_24:
cmpb SIGN_POS,SIGN(%edi)
je LDown_24_pos
movl %eax,%ecx
andl $0x000000ff,%ecx
orl %ebx,%ecx
orl %edx,%ecx
jnz LDo_24_round_up
jmp L_store
LDown_24_pos:
movl %eax,%ecx
andl $0x000000ff,%ecx
orl %ebx,%ecx
orl %edx,%ecx
jnz LTruncate_24
jmp L_store
LRound_nearest_24:
// Do rounding of the 24th bit if needed (nearest or even)
movl %eax,%ecx
andl $0x000000ff,%ecx
cmpl $0x00000080,%ecx
jc LTruncate_24 // less than half, no increment needed
jne LGreater_Half_24 // greater than half, increment needed
// Possibly half, we need to check the ls bits
orl %ebx,%ebx
jne LGreater_Half_24 // greater than half, increment needed
orl %edx,%edx
jne LGreater_Half_24 // greater than half, increment needed
// Exactly half, increment only if 24th bit is 1 (round to even)
testl $0x00000100,%eax
jz LTruncate_24
LGreater_Half_24: // Rounding: increment at the 24th bit
LDo_24_round_up:
andl $0xffffff00,%eax // Truncate to 24 bits
xorl %ebx,%ebx
addl $0x00000100,%eax
jmp LCheck_Round_Overflow
LTruncate_24:
andl $0xffffff00,%eax // Truncate to 24 bits
xorl %ebx,%ebx
jmp L_store
LRound_To_53:
movl %esi,%ecx
andl CW_RC,%ecx
cmpl RC_RND,%ecx
je LRound_nearest_53
cmpl RC_CHOP,%ecx
je LTruncate_53
cmpl RC_UP,%ecx // Towards +infinity
je LUp_53
cmpl RC_DOWN,%ecx // Towards -infinity
je LDown_53
#ifdef PARANOID
jmp L_bugged
#endif PARANOID
LUp_53:
cmpb SIGN_POS,SIGN(%edi)
je LUp_53_pos
movl %ebx,%ecx
andl $0x000007ff,%ecx
orl %edx,%ecx
jnz LTruncate_53
jmp L_store
LUp_53_pos:
movl %ebx,%ecx
andl $0x000007ff,%ecx
orl %edx,%ecx
jnz LDo_53_round_up
jmp L_store
LDown_53:
cmpb SIGN_POS,SIGN(%edi)
je LDown_53_pos
movl %ebx,%ecx
andl $0x000007ff,%ecx
orl %edx,%ecx
jnz LDo_53_round_up
jmp L_store
LDown_53_pos:
movl %ebx,%ecx
andl $0x000007ff,%ecx
orl %edx,%ecx
jnz LTruncate_53
jmp L_store
LRound_nearest_53:
// Do rounding of the 53rd bit if needed (nearest or even)
movl %ebx,%ecx
andl $0x000007ff,%ecx
cmpl $0x00000400,%ecx
jc LTruncate_53 // less than half, no increment needed
jne LGreater_Half_53 // greater than half, increment needed
// Possibly half, we need to check the ls bits
orl %edx,%edx
jne LGreater_Half_53 // greater than half, increment needed
// Exactly half, increment only if 53rd bit is 1 (round to even)
testl $0x00000800,%ebx
jz LTruncate_53
LGreater_Half_53: // Rounding: increment at the 53rd bit
LDo_53_round_up:
andl $0xfffff800,%ebx // Truncate to 53 bits
addl $0x00000800,%ebx
adcl $0,%eax
jmp LCheck_Round_Overflow
LTruncate_53:
andl $0xfffff800,%ebx // Truncate to 53 bits
jmp L_store
LRound_To_64:
movl %esi,%ecx
andl CW_RC,%ecx
cmpl RC_RND,%ecx
je LRound_nearest_64
cmpl RC_CHOP,%ecx
je LTruncate_64
cmpl RC_UP,%ecx // Towards +infinity
je LUp_64
cmpl RC_DOWN,%ecx // Towards -infinity
je LDown_64
#ifdef PARANOID
jmp L_bugged
#endif PARANOID
LUp_64:
cmpb SIGN_POS,SIGN(%edi)
je LUp_64_pos
orl %edx,%edx
jnz LTruncate_64
jmp L_store
LUp_64_pos:
orl %edx,%edx
jnz LDo_64_round_up
jmp L_store
LDown_64:
cmpb SIGN_POS,SIGN(%edi)
je LDown_64_pos
orl %edx,%edx
jnz LDo_64_round_up
jmp L_store
LDown_64_pos:
orl %edx,%edx
jnz LTruncate_64
jmp L_store
LRound_nearest_64:
cmpl $0x80000000,%edx
jc LTruncate_64
jne LDo_64_round_up
/* Now test for round-to-even */
testb $1,%ebx
jz LTruncate_64
LDo_64_round_up:
addl $1,%ebx
adcl $0,%eax
LCheck_Round_Overflow:
jnc L_store /* Rounding done, no overflow */
/* Overflow, adjust the result (to 1.0) */
rcrl $1,%eax
rcrl $1,%ebx
incl EXP(%edi)
LTruncate_64:
L_store:
/* store the result */
movl %eax,SIGH(%edi)
movl %ebx,SIGL(%edi)
movb TW_Valid,TAG(%edi) /* Set the tags to TW_Valid */
// The number may have overflowed
cmpl EXP_OVER,EXP(%edi)
jge L_overflow
cmpl EXP_UNDER,EXP(%edi)
jle L_underflow
L_exit:
popl %ebx
popl %edi
popl %esi
leave
ret
/* The operations resulted in a number too large to represent */
L_overflow:
push %edi
call _arith_overflow
pop %edi
jmp L_exit
/* The operations resulted in a number too small to represent */
L_underflow:
pushl %edi
call _arith_underflow
popl %edi
jmp L_exit
#ifdef PARANOID
/* If we ever get here then we have problems! */
L_bugged:
pushl EX_INTERNAL|0x201
call EXCEPTION
pop %ebx
jmp L_exit
#endif PARANOID
...@@ -5,11 +5,13 @@ ...@@ -5,11 +5,13 @@
| Add two valid (TW_Valid) FPU_REG numbers, of the same sign, and put the | | Add two valid (TW_Valid) FPU_REG numbers, of the same sign, and put the |
| result in a destination FPU_REG. | | result in a destination FPU_REG. |
| | | |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | Copyright (C) 1992,1993 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au | | Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| | | |
| Call from C as: | | Call from C as: |
| void reg_u_add(reg *arg1, reg *arg2, reg *answ) | | void reg_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, |
| int control_w) |
| | | |
+---------------------------------------------------------------------------*/ +---------------------------------------------------------------------------*/
...@@ -24,6 +26,7 @@ ...@@ -24,6 +26,7 @@
#include "exception.h" #include "exception.h"
#include "fpu_asm.h" #include "fpu_asm.h"
#include "control_w.h"
.text .text
.align 2,144 .align 2,144
...@@ -59,7 +62,10 @@ L_arg1_larger: ...@@ -59,7 +62,10 @@ L_arg1_larger:
movl SIGH(%edi),%eax movl SIGH(%edi),%eax
L_accum_loaded: L_accum_loaded:
movl 16(%ebp),%edi /* destination */ movl PARAM3,%edi /* destination */
movb SIGN(%esi),%dl
movb %dl,SIGN(%edi) /* Copy the sign from the first arg */
movl EXP(%esi),%edx movl EXP(%esi),%edx
movl %edx,EXP(%edi) /* Copy exponent to destination */ movl %edx,EXP(%edi) /* Copy exponent to destination */
...@@ -74,6 +80,7 @@ L_accum_loaded: ...@@ -74,6 +80,7 @@ L_accum_loaded:
je L_bugged je L_bugged
#endif PARANOID #endif PARANOID
// The number to be shifted is in %eax:%ebx:%edx
cmpw $32,%cx /* shrd only works for 0..31 bits */ cmpw $32,%cx /* shrd only works for 0..31 bits */
jnc L_more_than_31 jnc L_more_than_31
...@@ -88,32 +95,43 @@ L_more_than_31: ...@@ -88,32 +95,43 @@ L_more_than_31:
jnc L_more_than_63 jnc L_more_than_63
subb $32,%cl subb $32,%cl
jz L_exactly_32
shrd %cl,%eax,%edx shrd %cl,%eax,%edx
shr %cl,%eax shr %cl,%eax
orl %ebx,%ebx
jz L_more_31_no_low // none of the lowest bits is set
orl $1,%edx // record the fact in the extension
L_more_31_no_low:
movl %eax,%ebx
xorl %eax,%eax
jmp L_shift_done
L_exactly_32:
movl %ebx,%edx
movl %eax,%ebx movl %eax,%ebx
xorl %eax,%eax xorl %eax,%eax
jmp L_shift_done jmp L_shift_done
L_more_than_63: L_more_than_63:
cmpw $66,%cx cmpw $65,%cx
jnc L_more_than_65 jnc L_more_than_64
subb $64,%cl
movl %eax,%edx movl %eax,%edx
shr %cl,%edx orl %ebx,%ebx
jz L_more_63_no_low
orl $1,%edx
jmp L_more_63_no_low
L_more_than_64:
movl $1,%edx // The shifted nr always at least one '1'
L_more_63_no_low:
xorl %ebx,%ebx xorl %ebx,%ebx
xorl %eax,%eax xorl %eax,%eax
jmp L_shift_done
L_more_than_65:
/* just copy the larger reg to dest */
movw SIGN(%esi),%ax
movw %ax,SIGN(%edi)
movl SIGL(%esi),%eax
movl %eax,SIGL(%edi)
movl SIGH(%esi),%eax
movl %eax,SIGH(%edi)
jmp L_exit // Does not overflow
L_shift_done: L_shift_done:
/* Now do the addition */ /* Now do the addition */
...@@ -125,56 +143,16 @@ L_shift_done: ...@@ -125,56 +143,16 @@ L_shift_done:
rcrl $1,%eax rcrl $1,%eax
rcrl $1,%ebx rcrl $1,%ebx
rcrl $1,%edx rcrl $1,%edx
jnc L_no_bit_lost
incl EXP(%edi) orl $1,%edx
L_round_the_result:
/* Round the result */
cmpl $0x80000000,%edx
jc L_no_round_up
jne L_do_round_up
/* Now test for round-to-even */
testb $1,%ebx
jz L_no_round_up
L_do_round_up:
addl $1,%ebx
adcl $0,%eax
jnc L_no_round_up /* Rounding done, no overflow */
/* Overflow, adjust the result */ L_no_bit_lost:
rcrl $1,%eax
rcrl $1,%ebx
incl EXP(%edi) incl EXP(%edi)
L_no_round_up: L_round_the_result:
/* store the result */ jmp FPU_round // Round the result
movl %eax,SIGH(%edi)
movl %ebx,SIGL(%edi)
movb TW_Valid,TAG(%edi) /* Set the tags to TW_Valid */
movb SIGN(%esi),%al
movb %al,SIGN(%edi) /* Copy the sign from the first arg */
// The number may have overflowed
cmpl EXP_OVER,EXP(%edi)
jge L_overflow
L_exit:
popl %ebx
popl %edi
popl %esi
leave
ret
/* The addition resulted in a number too large to represent */
L_overflow:
push %edi
call _arith_overflow
pop %ebx
jmp L_exit
#ifdef PARANOID #ifdef PARANOID
...@@ -185,3 +163,11 @@ L_bugged: ...@@ -185,3 +163,11 @@ L_bugged:
pop %ebx pop %ebx
jmp L_exit jmp L_exit
#endif PARANOID #endif PARANOID
L_exit:
popl %ebx
popl %edi
popl %esi
leave
ret
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -9,5 +9,5 @@ ...@@ -9,5 +9,5 @@
| | | |
+---------------------------------------------------------------------------*/ +---------------------------------------------------------------------------*/
#define FPU_VERSION "wm-FPU-emu version BETA 1.2" #define FPU_VERSION "wm-FPU-emu version BETA 1.3"
This diff is collapsed.
...@@ -1031,7 +1031,7 @@ void do_fd_request(void) ...@@ -1031,7 +1031,7 @@ void do_fd_request(void)
} }
static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned int param) unsigned long param)
{ {
int i,drive,cnt,okay; int i,drive,cnt,okay;
struct floppy_struct *this; struct floppy_struct *this;
......
...@@ -305,6 +305,8 @@ static void read_intr(void) ...@@ -305,6 +305,8 @@ static void read_intr(void)
do { do {
i = (unsigned) inb_p(HD_STATUS); i = (unsigned) inb_p(HD_STATUS);
if (i & BUSY_STAT)
continue;
if ((i & STAT_MASK) != STAT_OK) if ((i & STAT_MASK) != STAT_OK)
break; break;
if (i & DRQ_STAT) if (i & DRQ_STAT)
...@@ -354,6 +356,8 @@ static void write_intr(void) ...@@ -354,6 +356,8 @@ static void write_intr(void)
do { do {
i = (unsigned) inb_p(HD_STATUS); i = (unsigned) inb_p(HD_STATUS);
if (i & BUSY_STAT)
continue;
if ((i & STAT_MASK) != STAT_OK) if ((i & STAT_MASK) != STAT_OK)
break; break;
if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT)) if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT))
...@@ -503,7 +507,7 @@ static void do_hd_request(void) ...@@ -503,7 +507,7 @@ static void do_hd_request(void)
} }
static int hd_ioctl(struct inode * inode, struct file * file, static int hd_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned int arg) unsigned int cmd, unsigned long arg)
{ {
struct hd_geometry *loc = (void *) arg; struct hd_geometry *loc = (void *) arg;
int dev, err; int dev, err;
......
...@@ -66,8 +66,7 @@ static int aha1542_last_mbo_used = (AHA1542_MAILBOXES - 1); ...@@ -66,8 +66,7 @@ static int aha1542_last_mbo_used = (AHA1542_MAILBOXES - 1);
static long WAITnexttimeout = 3000000; static long WAITnexttimeout = 3000000;
static int aha1542_host = 0; static int aha1542_host = 0;
static void setup_mailboxes(); static void setup_mailboxes(void);
extern void aha1542_interrupt();
#define aha1542_intr_reset() outb(IRST, CONTROL) #define aha1542_intr_reset() outb(IRST, CONTROL)
...@@ -530,7 +529,7 @@ int aha1542_command(Scsi_Cmnd * SCpnt) ...@@ -530,7 +529,7 @@ int aha1542_command(Scsi_Cmnd * SCpnt)
} }
/* Initialize mailboxes */ /* Initialize mailboxes */
static void setup_mailboxes() static void setup_mailboxes(void)
{ {
int i; int i;
static unchar cmd[5] = {CMD_MBINIT, AHA1542_MAILBOXES}; static unchar cmd[5] = {CMD_MBINIT, AHA1542_MAILBOXES};
......
...@@ -193,6 +193,8 @@ static void scan_scsis (void) ...@@ -193,6 +193,8 @@ static void scan_scsis (void)
SCmd.request.dev = 0xffff; /* Mark not busy */ SCmd.request.dev = 0xffff; /* Mark not busy */
SCmd.use_sg = 0; SCmd.use_sg = 0;
SCmd.transfersize = 0;
SCmd.underflow = 0;
scsi_do_cmd (&SCmd, scsi_do_cmd (&SCmd,
(void *) scsi_cmd, (void *) (void *) scsi_cmd, (void *)
...@@ -445,6 +447,8 @@ Scsi_Cmnd * request_queueable (struct request * req, int index) ...@@ -445,6 +447,8 @@ Scsi_Cmnd * request_queueable (struct request * req, int index)
}; };
SCpnt->use_sg = 0; /* Reset the scatter-gather flag */ SCpnt->use_sg = 0; /* Reset the scatter-gather flag */
SCpnt->transfersize = 0;
SCpnt->underflow = 0;
return SCpnt; return SCpnt;
} }
...@@ -516,6 +520,8 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, int index, int wait) ...@@ -516,6 +520,8 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, int index, int wait)
}; };
SCpnt->use_sg = 0; /* Reset the scatter-gather flag */ SCpnt->use_sg = 0; /* Reset the scatter-gather flag */
SCpnt->transfersize = 0; /* No default transfer size */
SCpnt->underflow = 0; /* Do not flag underflow conditions */
return SCpnt; return SCpnt;
} }
...@@ -929,7 +935,8 @@ static void scsi_done (Scsi_Cmnd * SCpnt) ...@@ -929,7 +935,8 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
} }
break; break;
default: default:
panic ("unsupported message byte recieved."); printk("scsi: unsupported message byte %d recieved\n", msg_byte(result));
panic ("");
} }
break; break;
case DID_TIME_OUT: case DID_TIME_OUT:
...@@ -1387,6 +1394,8 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end ...@@ -1387,6 +1394,8 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
SCpnt->index = i; SCpnt->index = i;
SCpnt->request.dev = -1; /* Mark not busy */ SCpnt->request.dev = -1; /* Mark not busy */
SCpnt->use_sg = 0; SCpnt->use_sg = 0;
SCpnt->underflow = 0;
SCpnt->transfersize = 0;
host = scsi_devices[i].host_no; host = scsi_devices[i].host_no;
if(host_queue[host]) if(host_queue[host])
host_queue[host]->prev = SCpnt; host_queue[host]->prev = SCpnt;
......
...@@ -351,11 +351,20 @@ typedef struct scsi_cmnd { ...@@ -351,11 +351,20 @@ typedef struct scsi_cmnd {
void * request_buffer; /* Actual requested buffer */ void * request_buffer; /* Actual requested buffer */
/* These elements define the operation we ultimately want to perform */ /* These elements define the operation we ultimately want to perform */
unsigned char data_cmnd[10]; unsigned char data_cmnd[12];
unsigned short use_sg; /* Number of pieces of scatter-gather */ unsigned short use_sg; /* Number of pieces of scatter-gather */
unsigned short sglist_len; /* size of malloc'd scatter-gather list */ unsigned short sglist_len; /* size of malloc'd scatter-gather list */
unsigned bufflen; /* Size of data buffer */ unsigned bufflen; /* Size of data buffer */
void *buffer; /* Data buffer */ void *buffer; /* Data buffer */
unsigned underflow; /* Return error if less than this amount is
transfered */
unsigned transfersize; /* How much we are guranteed to transfer with
each SCSI transfer (ie, between disconnect /
reconnects. Probably == sector size */
struct request request; /* A copy of the command we are working on*/ struct request request; /* A copy of the command we are working on*/
......
This diff is collapsed.
This diff is collapsed.
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg); extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
extern int revalidate_scsidisk(int, int); extern int revalidate_scsidisk(int, int);
int sd_ioctl(struct inode * inode, struct file * file, unsigned long cmd, unsigned long arg) int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
{ {
int dev = inode->i_rdev; int dev = inode->i_rdev;
int host, error; int host, error;
......
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