diff -u --recursive --new-file v1.1.17/linux/Makefile linux/Makefile --- v1.1.17/linux/Makefile Thu Jun 2 13:50:54 1994 +++ linux/Makefile Thu Jun 2 10:56:25 1994 @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 1 -SUBLEVEL = 17 +SUBLEVEL = 18 all: Version zImage diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/Makefile linux/drivers/FPU-emu/Makefile --- v1.1.17/linux/drivers/FPU-emu/Makefile Tue Jan 11 11:10:47 1994 +++ linux/drivers/FPU-emu/Makefile Thu Jun 2 10:28:22 1994 @@ -5,14 +5,13 @@ #DEBUG = -DDEBUGGING DEBUG = PARANOID = -DPARANOID -REENTRANT = -DREENTRANT_FPU CFLAGS := $(CFLAGS) $(PARANOID) $(DEBUG) -fno-builtin .c.o: $(CC) $(CFLAGS) $(MATH_EMULATION) -c $< .S.o: - $(CC) -D__ASSEMBLER__ $(PARANOID) $(REENTRANT) -c $< + $(CC) -D__ASSEMBLER__ $(PARANOID) -c $< .s.o: $(CC) -c $< diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/README linux/drivers/FPU-emu/README --- v1.1.17/linux/drivers/FPU-emu/README Sat Mar 26 14:04:23 1994 +++ linux/drivers/FPU-emu/README Thu Jun 2 10:28:23 1994 @@ -47,7 +47,7 @@ --Bill Metzenthen - March 1994 + June 1994 ----------------------- Internals of wm-FPU-emu ----------------------- @@ -80,20 +80,24 @@ However, it may happen that when the emulator is accessing the user memory space, swapping may be needed. In this case the emulator may be temporarily suspended while disk i/o takes place. During this time -another process may use the emulator, thereby changing some static -variables (eg FPU_st0_ptr, etc). The code which accesses user memory -is confined to five files: +another process may use the emulator, thereby perhaps changing static +variables. The code which accesses user memory is confined to five +files: fpu_entry.c reg_ld_str.c load_store.c get_address.c errors.c +As from version 1.12 of the emulator, no static variables are used +(apart from those in the kernel's per-process tables). The emulator is +therefore now fully re-entrant, rather than having just the restricted +form of re-entrancy which is required by the Linux kernel. ----------------------- Limitations of wm-FPU-emu ----------------------- There are a number of differences between the current wm-FPU-emu -(version beta 1.11) and the 80486 FPU (apart from bugs). Some of the -more important differences are listed below: +(version 1.12) and the 80486 FPU (apart from bugs). Some of the more +important differences are listed below: The Roundup flag does not have much meaning for the transcendental functions and its 80486 value with these functions is likely to differ @@ -154,6 +158,11 @@ protection fault message when run under the MS-DOS prompt of Windows 3.1. (The program simply reads data from a valid address). +The emulator supports 16-bit protected mode, with one difference from +an 80486DX. A 80486DX will allow some floating point instructions to +write a few bytes below the lowest address of the stack. The emulator +will not allow this in 16-bit protected mode: no instructions are +allowed to write outside the bounds set by the protection. ----------------------- Performance of wm-FPU-emu ----------------------- @@ -322,6 +331,7 @@ Bruce Evans, bde@kralizec.zeta.org.au Timo Korvola, Timo.Korvola@hut.fi Rick Lyons, rick@razorback.brisnet.org.au +Rick, jrs@world.std.com ...and numerous others who responded to my request for help with a real 80486. diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/errors.c linux/drivers/FPU-emu/errors.c --- v1.1.17/linux/drivers/FPU-emu/errors.c Fri Feb 25 14:42:45 1994 +++ linux/drivers/FPU-emu/errors.c Thu Jun 2 10:28:23 1994 @@ -42,20 +42,28 @@ RE_ENTRANT_CHECK_OFF; /* No need to verify_area(), we have previously fetched these bytes. */ printk("Unimplemented FPU Opcode at eip=%p : ", (void *) address); - while ( 1 ) + if ( FPU_CS == USER_CS ) { - byte1 = get_fs_byte((unsigned char *) address); - if ( (byte1 & 0xf8) == 0xd8 ) break; - printk("[%02x]", byte1); - address++; + while ( 1 ) + { + byte1 = get_fs_byte((unsigned char *) address); + if ( (byte1 & 0xf8) == 0xd8 ) break; + printk("[%02x]", byte1); + address++; + } + printk("%02x ", byte1); + FPU_modrm = get_fs_byte(1 + (unsigned char *) address); + + if (FPU_modrm >= 0300) + printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7); + else + printk("/%d\n", (FPU_modrm >> 3) & 7); } - printk("%02x ", byte1); - FPU_modrm = get_fs_byte(1 + (unsigned char *) address); - - if (FPU_modrm >= 0300) - printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7); else - printk("/%d\n", (FPU_modrm >> 3) & 7); + { + printk("cs selector = %04x\n", FPU_CS); + } + RE_ENTRANT_CHECK_ON; EXCEPTION(EX_Invalid); @@ -85,29 +93,36 @@ RE_ENTRANT_CHECK_OFF; /* No need to verify_area(), we have previously fetched these bytes. */ printk("At %p:", (void *) address); -#define MAX_PRINTED_BYTES 20 - for ( i = 0; i < MAX_PRINTED_BYTES; i++ ) + if ( FPU_CS == USER_CS ) { - byte1 = get_fs_byte((unsigned char *) address); - if ( (byte1 & 0xf8) == 0xd8 ) +#define MAX_PRINTED_BYTES 20 + for ( i = 0; i < MAX_PRINTED_BYTES; i++ ) { - printk(" %02x", byte1); - break; + byte1 = get_fs_byte((unsigned char *) address); + if ( (byte1 & 0xf8) == 0xd8 ) + { + printk(" %02x", byte1); + break; + } + printk(" [%02x]", byte1); + address++; + } + if ( i == MAX_PRINTED_BYTES ) + printk(" [more..]\n"); + else + { + FPU_modrm = get_fs_byte(1 + (unsigned char *) address); + + if (FPU_modrm >= 0300) + printk(" %02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7); + else + printk(" /%d, mod=%d rm=%d\n", + (FPU_modrm >> 3) & 7, (FPU_modrm >> 6) & 3, FPU_modrm & 7); } - printk(" [%02x]", byte1); - address++; } - if ( i == MAX_PRINTED_BYTES ) - printk(" [more..]\n"); else { - FPU_modrm = get_fs_byte(1 + (unsigned char *) address); - - if (FPU_modrm >= 0300) - printk(" %02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7); - else - printk(" /%d, mod=%d rm=%d\n", - (FPU_modrm >> 3) & 7, (FPU_modrm >> 6) & 3, FPU_modrm & 7); + printk("%04x\n", FPU_CS); } partial_status = status_word(); @@ -181,6 +196,7 @@ printk("%s\n", tag_desc[(int) (unsigned) r->tag]); } +#ifdef OBSOLETE printk("[data] %c .%04lx %04lx %04lx %04lx e%+-6ld ", FPU_loaded_data.sign ? '-' : '+', (long)(FPU_loaded_data.sigh >> 16), @@ -189,6 +205,7 @@ (long)(FPU_loaded_data.sigl & 0xFFFF), FPU_loaded_data.exp - EXP_BIAS + 1); printk("%s\n", tag_desc[(int) (unsigned) FPU_loaded_data.tag]); +#endif OBSOLETE RE_ENTRANT_CHECK_ON; } @@ -214,7 +231,6 @@ error was detected. Internal error types: - 0 in load_store.c 0x14 in fpu_etc.c 0x1nn in a *.c file: 0x101 in reg_add_sub.c @@ -244,7 +260,13 @@ 0x126 in fpu_entry.c 0x127 in poly_2xm1.c 0x128 in fpu_entry.c + 0x129 in fpu_entry.c 0x130 in get_address.c + 0x131 in get_address.c + 0x132 in get_address.c + 0x133 in get_address.c + 0x140 in load_store.c + 0x141 in load_store.c 0x2nn in an *.S file: 0x201 in reg_u_add.S 0x202 in reg_u_div.S @@ -583,7 +605,7 @@ { /* The masked response */ top--; - reg_move(&CONST_QNaN, FPU_st0_ptr = &st(0)); + reg_move(&CONST_QNaN, &st(0)); } EXCEPTION(EX_StackOver); @@ -599,7 +621,7 @@ if ( control_word & CW_Invalid ) { /* The masked response */ - reg_move(&CONST_QNaN, FPU_st0_ptr); + reg_move(&CONST_QNaN, &st(0)); } EXCEPTION(EX_StackUnder); diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/fpu_arith.c linux/drivers/FPU-emu/fpu_arith.c --- v1.1.17/linux/drivers/FPU-emu/fpu_arith.c Wed Dec 1 14:44:16 1993 +++ linux/drivers/FPU-emu/fpu_arith.c Thu Jun 2 10:28:23 1994 @@ -20,7 +20,7 @@ { /* fadd st,st(i) */ clear_C1(); - reg_add(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word); + reg_add(&st(0), &st(FPU_rm), &st(0), control_word); } @@ -28,7 +28,7 @@ { /* fmul st,st(i) */ clear_C1(); - reg_mul(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word); + reg_mul(&st(0), &st(FPU_rm), &st(0), control_word); } @@ -37,7 +37,7 @@ { /* fsub st,st(i) */ clear_C1(); - reg_sub(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word); + reg_sub(&st(0), &st(FPU_rm), &st(0), control_word); } @@ -45,7 +45,7 @@ { /* fsubr st,st(i) */ clear_C1(); - reg_sub(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr, control_word); + reg_sub(&st(FPU_rm), &st(0), &st(0), control_word); } @@ -53,7 +53,7 @@ { /* fdiv st,st(i) */ clear_C1(); - reg_div(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word); + reg_div(&st(0), &st(FPU_rm), &st(0), control_word); } @@ -61,7 +61,7 @@ { /* fdivr st,st(i) */ clear_C1(); - reg_div(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr, control_word); + reg_div(&st(FPU_rm), &st(0), &st(0), control_word); } @@ -70,7 +70,7 @@ { /* fadd st(i),st */ clear_C1(); - reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word); + reg_add(&st(0), &st(FPU_rm), &st(FPU_rm), control_word); } @@ -78,7 +78,7 @@ { /* fmul st(i),st */ clear_C1(); - reg_mul(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word); + reg_mul(&st(0), &st(FPU_rm), &st(FPU_rm), control_word); } @@ -86,9 +86,9 @@ { /* fsubr st(i),st */ /* This is the sense of the 80486 manual - reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word); */ + reg_sub(&st(FPU_rm), &st(0), &st(FPU_rm), control_word); */ clear_C1(); - reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word); + reg_sub(&st(0), &st(FPU_rm), &st(FPU_rm), control_word); } @@ -96,9 +96,9 @@ { /* fsub st(i),st */ /* This is the sense of the 80486 manual - reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word); */ + reg_sub(&st(0), &st(FPU_rm), &st(FPU_rm), control_word); */ clear_C1(); - reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word); + reg_sub(&st(FPU_rm), &st(0), &st(FPU_rm), control_word); } @@ -106,7 +106,7 @@ { /* fdivr st(i),st */ clear_C1(); - reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word); + reg_div(&st(0), &st(FPU_rm), &st(FPU_rm), control_word); } @@ -114,7 +114,7 @@ { /* fdiv st(i),st */ clear_C1(); - reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word); + reg_div(&st(FPU_rm), &st(0), &st(FPU_rm), control_word); } @@ -123,7 +123,7 @@ { /* faddp st(i),st */ clear_C1(); - if ( !reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word) ) + if ( !reg_add(&st(0), &st(FPU_rm), &st(FPU_rm), control_word) ) pop(); } @@ -132,7 +132,7 @@ { /* fmulp st(i),st */ clear_C1(); - if ( !reg_mul(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word) ) + if ( !reg_mul(&st(0), &st(FPU_rm), &st(FPU_rm), control_word) ) pop(); } @@ -142,9 +142,9 @@ { /* fsubrp st(i),st */ /* This is the sense of the 80486 manual - reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word); */ + reg_sub(&st(FPU_rm), &st(0), &st(FPU_rm), control_word); */ clear_C1(); - if ( !reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word) ) + if ( !reg_sub(&st(0), &st(FPU_rm), &st(FPU_rm), control_word) ) pop(); } @@ -153,9 +153,9 @@ { /* fsubp st(i),st */ /* This is the sense of the 80486 manual - reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word); */ + reg_sub(&st(0), &st(FPU_rm), &st(FPU_rm), control_word); */ clear_C1(); - if ( !reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word) ) + if ( !reg_sub(&st(FPU_rm), &st(0), &st(FPU_rm), control_word) ) pop(); } @@ -164,7 +164,7 @@ { /* fdivrp st(i),st */ clear_C1(); - if ( !reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word) ) + if ( !reg_div(&st(0), &st(FPU_rm), &st(FPU_rm), control_word) ) pop(); } @@ -173,7 +173,7 @@ { /* fdivp st(i),st */ clear_C1(); - if ( !reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word) ) + if ( !reg_div(&st(FPU_rm), &st(0), &st(FPU_rm), control_word) ) pop(); } diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/fpu_aux.c linux/drivers/FPU-emu/fpu_aux.c --- v1.1.17/linux/drivers/FPU-emu/fpu_aux.c Mon Feb 7 09:35:20 1994 +++ linux/drivers/FPU-emu/fpu_aux.c Thu Jun 2 10:28:23 1994 @@ -26,8 +26,7 @@ partial_status &= ~(SW_Backward|SW_Summary|SW_Stack_Fault|SW_Precision| SW_Underflow|SW_Overflow|SW_Zero_Div|SW_Denorm_Op| SW_Invalid); - NO_NET_DATA_EFFECT; - FPU_entry_eip = ip_offset; /* We want no net effect */ + no_ip_update = 1; } /* Needs to be externally visible */ @@ -43,11 +42,12 @@ } /* The behaviour is different to that detailed in Section 15.1.6 of the Intel manual */ - data_operand_offset = 0; - operand_selector = 0; - NO_NET_DATA_EFFECT; - FPU_entry_op_cs = 0; - FPU_entry_eip = ip_offset = 0; + operand_address.offset = 0; + operand_address.selector = 0; + instruction_address.offset = 0; + instruction_address.selector = 0; + instruction_address.opcode = 0; + no_ip_update = 1; } /* @@ -71,7 +71,7 @@ static void fstsw_ax(void) { *(short *) &FPU_EAX = status_word(); - NO_NET_INSTR_EFFECT; + no_ip_update = 1; } static FUNC const fstsw_table[] = { @@ -108,10 +108,9 @@ { reg_move(&st(FPU_rm), st_new_ptr); push(); } else { - if ( control_word & EX_Invalid ) + if ( control_word & CW_Invalid ) { /* The masked response */ - push(); stack_underflow(); } else @@ -125,9 +124,9 @@ { /* fxch st(i) */ FPU_REG t; - register FPU_REG *sti_ptr = &st(FPU_rm); + register FPU_REG *sti_ptr = &st(FPU_rm), *st0_ptr = &st(0); - if ( FPU_st0_tag == TW_Empty ) + if ( st0_ptr->tag == TW_Empty ) { if ( sti_ptr->tag == TW_Empty ) { @@ -136,20 +135,20 @@ return; } if ( control_word & CW_Invalid ) - reg_move(sti_ptr, FPU_st0_ptr); /* Masked response */ + reg_move(sti_ptr, st0_ptr); /* Masked response */ stack_underflow_i(FPU_rm); return; } if ( sti_ptr->tag == TW_Empty ) { if ( control_word & CW_Invalid ) - reg_move(FPU_st0_ptr, sti_ptr); /* Masked response */ + reg_move(st0_ptr, sti_ptr); /* Masked response */ stack_underflow(); return; } clear_C1(); - reg_move(FPU_st0_ptr, &t); - reg_move(sti_ptr, FPU_st0_ptr); + reg_move(st0_ptr, &t); + reg_move(sti_ptr, st0_ptr); reg_move(&t, sti_ptr); } @@ -172,14 +171,14 @@ void fst_i_() { /* fst st(i) */ - reg_move(FPU_st0_ptr, &st(FPU_rm)); + reg_move(&st(0), &st(FPU_rm)); } void fstp_i() { /* fstp st(i) */ - reg_move(FPU_st0_ptr, &st(FPU_rm)); + reg_move(&st(0), &st(FPU_rm)); pop(); } diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/fpu_emu.h linux/drivers/FPU-emu/fpu_emu.h --- v1.1.17/linux/drivers/FPU-emu/fpu_emu.h Tue May 24 00:34:46 1994 +++ linux/drivers/FPU-emu/fpu_emu.h Thu Jun 2 10:28:23 1994 @@ -60,14 +60,18 @@ #include #include -#ifdef PARANOID +/* +#define RE_ENTRANT_CHECKING + */ + +#ifdef RE_ENTRANT_CHECKING extern char emulating; # define RE_ENTRANT_CHECK_OFF emulating = 0 # define RE_ENTRANT_CHECK_ON emulating = 1 #else # define RE_ENTRANT_CHECK_OFF # define RE_ENTRANT_CHECK_ON -#endif PARANOID +#endif RE_ENTRANT_CHECKING #define FWAIT_OPCODE 0x9b #define OP_SIZE_PREFIX 0x66 @@ -89,46 +93,43 @@ #define PREFIX_SS_ 6 #define PREFIX_DEFAULT 7 -/* These are to defeat the default action, giving the instruction - no net effect: */ -#define NO_NET_DATA_EFFECT \ - { FPU_data_address = (void *)data_operand_offset; \ - FPU_data_selector = operand_selector; } -#define NO_NET_INSTR_EFFECT \ - { FPU_entry_eip = ip_offset; \ - FPU_entry_op_cs = cs_selector; } - - +struct address { + unsigned int offset; + unsigned int selector:16; + unsigned int opcode:11; + unsigned int empty:5; +}; typedef void (*FUNC)(void); typedef struct fpu_reg FPU_REG; +typedef void (*FUNC_ST0)(FPU_REG *st0_ptr); typedef struct { unsigned char address_size, operand_size, segment; } overrides; -/* This structure is 48 bits: */ +/* This structure is 32 bits: */ typedef struct { overrides override; - unsigned char mode16, vm86, p286; } fpu_addr_modes; + unsigned char default_mode; } fpu_addr_modes; +/* PROTECTED has a restricted meaning in the emulator; it is used + to signal that the emulator needs to do special things to ensure + that protection is respected in a segmented model. */ +#define PROTECTED 4 +#define SIXTEEN 1 /* We rely upon this being 1 (true) */ +#define VM86 SIXTEEN +#define PM16 (SIXTEEN | PROTECTED) +#define SEG32 PROTECTED +extern unsigned char const data_sizes_16[32]; #define st(x) ( regs[((top+x) &7 )] ) #define STACK_OVERFLOW (st_new_ptr = &st(-1), st_new_ptr->tag != TW_Empty) #define NOT_EMPTY(i) (st(i).tag != TW_Empty) -#define NOT_EMPTY_0 (FPU_st0_tag ^ TW_Empty) - -extern unsigned char FPU_rm; - -extern char FPU_st0_tag; -extern FPU_REG *FPU_st0_ptr; - -/* ###### These need to be shifted to somewhere safe. */ -/* extern void *FPU_data_address; has been shifted */ -extern unsigned short FPU_data_selector; -extern unsigned long FPU_entry_op_cs; - -extern FPU_REG FPU_loaded_data; +#define NOT_EMPTY_ST0 (st0_tag ^ TW_Empty) -#define pop() { FPU_st0_ptr->tag = TW_Empty; top++; } +#define pop() { regs[(top++ & 7 )].tag = TW_Empty; } +#define poppop() { regs[((top + 1) & 7 )].tag \ + = regs[(top & 7 )].tag = TW_Empty; \ + top += 2; } /* push() does not affect the tags */ -#define push() { top--; FPU_st0_ptr = st_new_ptr; } +#define push() { top--; } #define reg_move(x, y) { \ diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/fpu_entry.c linux/drivers/FPU-emu/fpu_entry.c --- v1.1.17/linux/drivers/FPU-emu/fpu_entry.c Tue May 24 00:34:46 1994 +++ linux/drivers/FPU-emu/fpu_entry.c Thu Jun 2 10:28:24 1994 @@ -122,39 +122,36 @@ #endif NO_UNDOC_CODE -/* Be careful when using any of these global variables... - they might change if swapping is triggered */ -unsigned char FPU_rm; -char FPU_st0_tag; -FPU_REG *FPU_st0_ptr; - -/* ######## To be shifted */ -unsigned long FPU_entry_op_cs; -unsigned short FPU_data_selector; - - -#ifdef PARANOID +#ifdef RE_ENTRANT_CHECKING char emulating=0; -#endif PARANOID +#endif RE_ENTRANT_CHECKING static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip, overrides *override); - asmlinkage void math_emulate(long arg) { unsigned char FPU_modrm, byte1; unsigned short code; fpu_addr_modes addr_modes; int unmasked; + FPU_REG loaded_data; + void *data_address; + struct address data_sel_off; + struct address entry_sel_off; + unsigned long code_base = 0; + unsigned long code_limit = 0; /* Initialized to stop compiler warnings */ + char st0_tag; + FPU_REG *st0_ptr; + struct desc_struct code_descriptor; -#ifdef PARANOID +#ifdef RE_ENTRANT_CHECKING if ( emulating ) { printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n"); } RE_ENTRANT_CHECK_ON; -#endif PARANOID +#endif RE_ENTRANT_CHECKING if (!current->used_math) { @@ -172,34 +169,51 @@ SETUP_DATA_AREA(arg); - addr_modes.vm86 = (FPU_EFLAGS & 0x00020000) != 0; - addr_modes.p286 = (!addr_modes.vm86 - && current->ldt - && (current->ldt[FPU_CS >> 3].b & 0xf000) == 0xf000 - && (current->ldt[FPU_CS >> 3].b & (1 << 22)) == 0); - addr_modes.mode16 = addr_modes.vm86 | addr_modes.p286; - - if ( addr_modes.vm86 ) - FPU_EIP += FPU_CS << 4; - else if ( addr_modes.p286 ) - FPU_EIP += LDT_BASE_ADDR(FPU_CS); - FPU_ORIG_EIP = FPU_EIP; - if ( !addr_modes.mode16 ) + if ( (FPU_EFLAGS & 0x00020000) != 0 ) + { + /* Virtual 8086 mode */ + addr_modes.default_mode = VM86; + FPU_EIP += code_base = FPU_CS << 4; + code_limit = code_base + 0xffff; /* Assumes code_base <= 0xffff0000 */ + } + else if ( FPU_CS == USER_CS && FPU_DS == USER_DS ) + { + addr_modes.default_mode = 0; + } + else if ( FPU_CS == KERNEL_CS ) { - /* user code space? */ - if (FPU_CS == KERNEL_CS) + printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP); + panic("Math emulation needed in kernel"); + } + else + { + + if ( (FPU_CS & 4) != 4 ) /* Must be in the LDT */ { - printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP); - panic("Math emulation needed in kernel"); + /* Can only handle segmented addressing via the LDT + for now, and it must be 16 bit */ + printk("FPU emulator: Unsupported addressing mode\n"); + math_abort(FPU_info, SIGILL); } - /* We cannot handle multiple segments yet */ - if (FPU_CS != USER_CS || FPU_DS != USER_DS) + if ( SEG_D_SIZE(code_descriptor = LDT_DESCRIPTOR(FPU_CS)) ) + { + /* The above test may be wrong, the book is not clear */ + /* Segmented 32 bit protected mode */ + addr_modes.default_mode = SEG32; + } + else { - math_abort(FPU_info,SIGILL); + /* 16 bit protected mode */ + addr_modes.default_mode = PM16; } + FPU_EIP += code_base = SEG_BASE_ADDR(code_descriptor); + code_limit = code_base + + (SEG_LIMIT(code_descriptor)+1) * SEG_GRANULARITY(code_descriptor) + - 1; + if ( code_limit < code_base ) code_limit = 0xffffffff; } FPU_lookahead = 1; @@ -220,14 +234,17 @@ do_another_FPU_instruction: + no_ip_update = 0; + FPU_EIP++; /* We have fetched the prefix and first code bytes. */ -#ifdef PECULIAR_486 - /* It would be more logical to do this only in get_address(), - but although it is supposed to be undefined for many fpu - instructions, an 80486 behaves as if this were done here: */ - FPU_data_selector = FPU_DS; -#endif PECULIAR_486 + if ( addr_modes.default_mode ) + { + /* This checks for the minimum instruction bytes. + We also need to check any extra (address mode) code access. */ + if ( FPU_EIP > code_limit ) + math_abort(FPU_info,SIGSEGV); + } if ( (byte1 & 0xf8) != 0xd8 ) { @@ -273,9 +290,8 @@ * via the cs selector and operand selector, so we do the same. */ do_the_FPU_interrupt: - cs_selector &= 0xffff0000; - cs_selector |= status_word(); - operand_selector = tag_word(); + instruction_address.selector = status_word(); + operand_address.selector = tag_word(); partial_status = 0; top = 0; { @@ -288,11 +304,6 @@ FPU_EIP = FPU_ORIG_EIP; /* Point to current FPU instruction. */ - if ( addr_modes.vm86 ) - FPU_EIP -= FPU_CS << 4; - else if ( addr_modes.p286 ) - FPU_EIP -= LDT_BASE_ADDR(FPU_CS); - RE_ENTRANT_CHECK_OFF; current->tss.trap_no = 16; current->tss.error_code = 0; @@ -301,57 +312,74 @@ } } - FPU_entry_eip = FPU_ORIG_EIP; - - FPU_entry_op_cs = (byte1 << 24) | (FPU_modrm << 16) | (FPU_CS & 0xffff) ; + entry_sel_off.offset = FPU_ORIG_EIP; + entry_sel_off.selector = FPU_CS; + entry_sel_off.opcode = (byte1 << 8) | FPU_modrm; FPU_rm = FPU_modrm & 7; if ( FPU_modrm < 0300 ) { /* All of these instructions use the mod/rm byte to get a data address */ - if ( addr_modes.vm86 + + if ( (addr_modes.default_mode & SIXTEEN) ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX) ) - get_address_16(FPU_modrm, &FPU_EIP, addr_modes); + data_address = get_address_16(FPU_modrm, &FPU_EIP, &data_sel_off, + addr_modes); else - get_address(FPU_modrm, &FPU_EIP, addr_modes); + data_address = get_address(FPU_modrm, &FPU_EIP, &data_sel_off, + addr_modes); + + if ( addr_modes.default_mode ) + { + if ( FPU_EIP-1 > code_limit ) + math_abort(FPU_info,SIGSEGV); + } if ( !(byte1 & 1) ) { unsigned short status1 = partial_status; - FPU_st0_ptr = &st(0); - FPU_st0_tag = FPU_st0_ptr->tag; + + st0_ptr = &st(0); + st0_tag = st0_ptr->tag; /* Stack underflow has priority */ - if ( NOT_EMPTY_0 ) + if ( NOT_EMPTY_ST0 ) { + if ( addr_modes.default_mode & PROTECTED ) + { + /* This table works for 16 and 32 bit protected mode */ + if ( access_limit < data_sizes_16[(byte1 >> 1) & 3] ) + math_abort(FPU_info,SIGSEGV); + } + unmasked = 0; /* Do this here to stop compiler warnings. */ switch ( (byte1 >> 1) & 3 ) { case 0: - unmasked = reg_load_single(); + unmasked = reg_load_single((float *)data_address, + &loaded_data); break; case 1: - reg_load_int32(); + reg_load_int32((long *)data_address, &loaded_data); break; case 2: - unmasked = reg_load_double(); + unmasked = reg_load_double((double *)data_address, + &loaded_data); break; case 3: - reg_load_int16(); + reg_load_int16((short *)data_address, &loaded_data); break; } /* No more access to user memory, it is safe to use static data now */ - FPU_st0_ptr = &st(0); - FPU_st0_tag = FPU_st0_ptr->tag; /* NaN operands have the next priority. */ /* We have to delay looking at st(0) until after loading the data, because that data might contain an SNaN */ - if ( (FPU_st0_tag == TW_NaN) || - (FPU_loaded_data.tag == TW_NaN) ) + if ( (st0_tag == TW_NaN) || + (loaded_data.tag == TW_NaN) ) { /* Restore the status word; we might have loaded a denormal. */ @@ -371,13 +399,13 @@ identical to an 80486 */ if ( (FPU_modrm & 0x28) == 0x20 ) /* fdiv or fsub */ - real_2op_NaN(&FPU_loaded_data, FPU_st0_ptr, - FPU_st0_ptr); + real_2op_NaN(&loaded_data, st0_ptr, + st0_ptr); else #endif PECULIAR_486 /* fadd, fdivr, fmul, or fsubr */ - real_2op_NaN(FPU_st0_ptr, &FPU_loaded_data, - FPU_st0_ptr); + real_2op_NaN(st0_ptr, &loaded_data, + st0_ptr); } goto reg_mem_instr_done; } @@ -388,11 +416,11 @@ if ( (FPU_modrm & 0x38) == 0x38 ) { /* fdivr */ - if ( (FPU_st0_tag == TW_Zero) && - (FPU_loaded_data.tag == TW_Valid) ) + if ( (st0_tag == TW_Zero) && + (loaded_data.tag == TW_Valid) ) { - if ( divide_by_zero(FPU_loaded_data.sign, - FPU_st0_ptr) ) + if ( divide_by_zero(loaded_data.sign, + st0_ptr) ) { /* We use the fact here that the unmasked exception in the loaded data was for a @@ -410,42 +438,42 @@ { case 0: /* fadd */ clear_C1(); - reg_add(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr, + reg_add(st0_ptr, &loaded_data, st0_ptr, control_word); break; case 1: /* fmul */ clear_C1(); - reg_mul(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr, + reg_mul(st0_ptr, &loaded_data, st0_ptr, control_word); break; case 2: /* fcom */ - compare_st_data(); + compare_st_data(&loaded_data); break; case 3: /* fcomp */ - if ( !compare_st_data() && !unmasked ) + if ( !compare_st_data(&loaded_data) && !unmasked ) pop(); break; case 4: /* fsub */ clear_C1(); - reg_sub(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr, + reg_sub(st0_ptr, &loaded_data, st0_ptr, control_word); break; case 5: /* fsubr */ clear_C1(); - reg_sub(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr, + reg_sub(&loaded_data, st0_ptr, st0_ptr, control_word); break; case 6: /* fdiv */ clear_C1(); - reg_div(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr, + reg_div(st0_ptr, &loaded_data, st0_ptr, control_word); break; case 7: /* fdivr */ clear_C1(); - if ( FPU_st0_tag == TW_Zero ) + if ( st0_tag == TW_Zero ) partial_status = status1; /* Undo any denorm tag, zero-divide has priority. */ - reg_div(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr, + reg_div(&loaded_data, st0_ptr, st0_ptr, control_word); break; } @@ -463,19 +491,19 @@ else stack_underflow(); } + reg_mem_instr_done: + operand_address = data_sel_off; } else { - load_store_instr(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1, - addr_modes); + if ( !(no_ip_update = + load_store_instr(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1, + addr_modes, data_address)) ) + { + operand_address = data_sel_off; + } } - reg_mem_instr_done: - -#ifndef PECULIAR_486 - *(unsigned short *)&operand_selector = FPU_data_selector; -#endif PECULIAR_486 - ; } else { @@ -485,38 +513,39 @@ #ifdef PECULIAR_486 /* This is supposed to be undefined, but a real 80486 seems to do this: */ - FPU_data_address = 0; + operand_address.offset = 0; + operand_address.selector = FPU_DS; #endif PECULIAR_486 - FPU_st0_ptr = &st(0); - FPU_st0_tag = FPU_st0_ptr->tag; + st0_ptr = &st(0); + st0_tag = st0_ptr->tag; switch ( type_table[(int) instr_index] ) { case _NONE_: /* also _REGIc: _REGIn */ break; case _REG0_: - if ( !NOT_EMPTY_0 ) + if ( !NOT_EMPTY_ST0 ) { stack_underflow(); goto FPU_instruction_done; } break; case _REGIi: - if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) ) + if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) ) { stack_underflow_i(FPU_rm); goto FPU_instruction_done; } break; case _REGIp: - if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) ) + if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) ) { stack_underflow_pop(FPU_rm); goto FPU_instruction_done; } break; case _REGI_: - if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) ) + if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) ) { stack_underflow(); goto FPU_instruction_done; @@ -532,17 +561,14 @@ goto FPU_instruction_done; } (*st_instr_table[(int) instr_index])(); - } FPU_instruction_done: + ; + } - ip_offset = FPU_entry_eip; - cs_selector = FPU_entry_op_cs; - data_operand_offset = (unsigned long)FPU_data_address; -#ifdef PECULIAR_486 - *(unsigned short *)&operand_selector = FPU_data_selector; -#endif PECULIAR_486 - + if ( ! no_ip_update ) + instruction_address = entry_sel_off; + FPU_fwait_done: #ifdef DEBUG @@ -553,16 +579,14 @@ if (FPU_lookahead && !need_resched) { - FPU_ORIG_EIP = FPU_EIP; + FPU_ORIG_EIP = FPU_EIP - code_base; if ( valid_prefix(&byte1, (unsigned char **)&FPU_EIP, &addr_modes.override) ) goto do_another_FPU_instruction; } - if ( addr_modes.vm86 ) - FPU_EIP -= FPU_CS << 4; - else if ( addr_modes.p286 ) - FPU_EIP -= LDT_BASE_ADDR(FPU_CS); + if ( addr_modes.default_mode ) + FPU_EIP -= code_base; RE_ENTRANT_CHECK_OFF; } diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/fpu_etc.c linux/drivers/FPU-emu/fpu_etc.c --- v1.1.17/linux/drivers/FPU-emu/fpu_etc.c Thu Feb 3 12:11:38 1994 +++ linux/drivers/FPU-emu/fpu_etc.c Thu Jun 2 10:28:24 1994 @@ -17,22 +17,22 @@ #include "reg_constant.h" -static void fchs(void) +static void fchs(FPU_REG *st0_ptr) { - if ( NOT_EMPTY_0 ) + if ( st0_ptr->tag ^ TW_Empty ) { - FPU_st0_ptr->sign ^= SIGN_POS^SIGN_NEG; + st0_ptr->sign ^= SIGN_POS^SIGN_NEG; clear_C1(); } else stack_underflow(); } -static void fabs(void) +static void fabs(FPU_REG *st0_ptr) { - if ( FPU_st0_tag ^ TW_Empty ) + if ( st0_ptr->tag ^ TW_Empty ) { - FPU_st0_ptr->sign = SIGN_POS; + st0_ptr->sign = SIGN_POS; clear_C1(); } else @@ -40,25 +40,25 @@ } -static void ftst_(void) +static void ftst_(FPU_REG *st0_ptr) { - switch (FPU_st0_tag) + switch (st0_ptr->tag) { case TW_Zero: setcc(SW_C3); break; case TW_Valid: - if (FPU_st0_ptr->sign == SIGN_POS) + if (st0_ptr->sign == SIGN_POS) setcc(0); else setcc(SW_C0); #ifdef DENORM_OPERAND - if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) { #ifdef PECULIAR_486 /* This is wierd! */ - if (FPU_st0_ptr->sign == SIGN_POS) + if (st0_ptr->sign == SIGN_POS) setcc(SW_C3); #endif PECULIAR_486 return; @@ -71,7 +71,7 @@ EXCEPTION(EX_Invalid); break; case TW_Infinity: - if (FPU_st0_ptr->sign == SIGN_POS) + if (st0_ptr->sign == SIGN_POS) setcc(0); else setcc(SW_C0); @@ -87,10 +87,10 @@ } } -static void fxam(void) +static void fxam(FPU_REG *st0_ptr) { int c=0; - switch (FPU_st0_tag) + switch (st0_ptr->tag) { case TW_Empty: c = SW_C3|SW_C0; @@ -100,7 +100,7 @@ break; case TW_Valid: /* This will need to be changed if TW_Denormal is ever used. */ - if ( FPU_st0_ptr->exp <= EXP_UNDER ) + if ( st0_ptr->exp <= EXP_UNDER ) c = SW_C2|SW_C3; /* Denormal */ else c = SW_C2; @@ -112,16 +112,18 @@ c = SW_C2|SW_C0; break; } - if (FPU_st0_ptr->sign == SIGN_NEG) + if (st0_ptr->sign == SIGN_NEG) c |= SW_C1; setcc(c); } -static FUNC const fp_etc_table[] = { - fchs, fabs, FPU_illegal, FPU_illegal, ftst_, fxam, FPU_illegal, FPU_illegal + +static FUNC_ST0 const fp_etc_table[] = { + fchs, fabs, (FUNC_ST0)FPU_illegal, (FUNC_ST0)FPU_illegal, + ftst_, fxam, (FUNC_ST0)FPU_illegal, (FUNC_ST0)FPU_illegal }; void fp_etc() { - (fp_etc_table[FPU_rm])(); + (fp_etc_table[FPU_rm])(&st(0)); } diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/fpu_proto.h linux/drivers/FPU-emu/fpu_proto.h --- v1.1.17/linux/drivers/FPU-emu/fpu_proto.h Wed Feb 16 13:07:56 1994 +++ linux/drivers/FPU-emu/fpu_proto.h Thu Jun 2 10:28:24 1994 @@ -63,13 +63,16 @@ extern void trig_b(void); /* get_address.c */ -extern void get_address(unsigned char FPU_modrm, unsigned long *fpu_eip, - fpu_addr_modes); -extern void get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip, - fpu_addr_modes); +extern void *get_address(unsigned char FPU_modrm, unsigned long *fpu_eip, + struct address *addr, + fpu_addr_modes); +extern void *get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip, + struct address *addr, + fpu_addr_modes); /* load_store.c */ -extern void load_store_instr(char type, fpu_addr_modes addr_modes); +extern int load_store_instr(unsigned char type, fpu_addr_modes addr_modes, + void *address); /* poly_2xm1.c */ extern int poly_2xm1(FPU_REG const *arg, FPU_REG *result); @@ -96,7 +99,7 @@ /* reg_compare.c */ extern int compare(FPU_REG const *b); -extern int compare_st_data(void); +extern int compare_st_data(FPU_REG const *b); extern void fcom_st(void); extern void fcompst(void); extern void fcompp(void); @@ -108,26 +111,26 @@ extern void fconst(void); /* reg_ld_str.c */ -extern int reg_load_extended(void); -extern int reg_load_double(void); -extern int reg_load_single(void); -extern void reg_load_int64(void); -extern void reg_load_int32(void); -extern void reg_load_int16(void); -extern void reg_load_bcd(void); -extern int reg_store_extended(void); -extern int reg_store_double(void); -extern int reg_store_single(void); -extern int reg_store_int64(void); -extern int reg_store_int32(void); -extern int reg_store_int16(void); -extern int reg_store_bcd(void); +extern int reg_load_extended(long double *addr, FPU_REG *loaded_data); +extern int reg_load_double(double *dfloat, FPU_REG *loaded_data); +extern int reg_load_single(float *single, FPU_REG *loaded_data); +extern void reg_load_int64(long long *_s, FPU_REG *loaded_data); +extern void reg_load_int32(long *_s, FPU_REG *loaded_data); +extern void reg_load_int16(short *_s, FPU_REG *loaded_data); +extern void reg_load_bcd(char *s, FPU_REG *loaded_data); +extern int reg_store_extended(long double *d, FPU_REG *st0_ptr); +extern int reg_store_double(double *dfloat, FPU_REG *st0_ptr); +extern int reg_store_single(float *single, FPU_REG *st0_ptr); +extern int reg_store_int64(long long *d, FPU_REG *st0_ptr); +extern int reg_store_int32(long *d, FPU_REG *st0_ptr); +extern int reg_store_int16(short *d, FPU_REG *st0_ptr); +extern int reg_store_bcd(char *d, FPU_REG *st0_ptr); extern int round_to_int(FPU_REG *r); -extern char *fldenv(fpu_addr_modes addr_modes); -extern void frstor(fpu_addr_modes addr_modes); +extern char *fldenv(fpu_addr_modes addr_modes, char *address); +extern void frstor(fpu_addr_modes addr_modes, char *address); extern unsigned short tag_word(void); -extern char *fstenv(fpu_addr_modes addr_modes); -extern void fsave(fpu_addr_modes addr_modes); +extern char *fstenv(fpu_addr_modes addr_modes, char *address); +extern void fsave(fpu_addr_modes addr_modes, char *address); /* reg_mul.c */ extern int reg_mul(FPU_REG const *a, FPU_REG const *b, diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/fpu_system.h linux/drivers/FPU-emu/fpu_system.h --- v1.1.17/linux/drivers/FPU-emu/fpu_system.h Tue May 24 00:34:46 1994 +++ linux/drivers/FPU-emu/fpu_system.h Thu Jun 2 10:28:24 1994 @@ -19,6 +19,19 @@ of the stack frame of math_emulate() */ #define SETUP_DATA_AREA(arg) FPU_info = (struct info *) &arg +#define LDT_DESCRIPTOR(s) (current->ldt[(s) >> 3]) +#define SEG_D_SIZE(x) ((x).b & (3 << 21)) +#define SEG_G_BIT(x) ((x).b & (1 << 23)) +#define SEG_GRANULARITY(x) (((x).b & (1 << 23)) ? 4096 : 1) +#define SEG_286_MODE(x) ((x).b & ( 0xff000000 | 0xf0000 | (1 << 23))) +#define SEG_BASE_ADDR(s) (((s).b & 0xff000000) \ + | (((s).b & 0xff) << 16) | ((s).a >> 16)) +#define SEG_LIMIT(s) (((s).b & 0xff0000) | ((s).a & 0xffff)) +#define SEG_EXECUTE_ONLY(s) (((s).b & ((1 << 11) | (1 << 9))) == (1 << 11)) +#define SEG_WRITE_PERM(s) (((s).b & ((1 << 11) | (1 << 9))) == (1 << 9)) +#define SEG_EXPAND_DOWN(s) (((s).b & ((1 << 11) | (1 << 10))) \ + == (1 << 10)) + #define I387 (current->tss.i387) #define FPU_info (I387.soft.info) @@ -30,22 +43,24 @@ #define FPU_EIP (FPU_info->___eip) #define FPU_ORIG_EIP (FPU_info->___orig_eip) -#define LDT_BASE_ADDR(s) ((current->ldt[(s) >> 3].b & 0xff000000) \ - | ((current->ldt[(s) >> 3].b & 0xff) << 16) \ - | (current->ldt[(s) >> 3].a >> 16)) - #define FPU_lookahead (I387.soft.lookahead) -#define FPU_entry_eip (I387.soft.entry_eip) +/* nz if ip_offset and cs_selector are not to be set for the current + instruction. */ +#define no_ip_update (((char *)&(I387.soft.twd))[0]) +#define FPU_rm (((unsigned char *)&(I387.soft.twd))[1]) + +/* Number of bytes of data which can be legally accessed by the current + instruction. This only needs to hold a number <= 108, so a byte will do. */ +#define access_limit (((unsigned char *)&(I387.soft.twd))[2]) + #define partial_status (I387.soft.swd) #define control_word (I387.soft.cwd) #define regs (I387.soft.regs) #define top (I387.soft.top) -#define ip_offset (I387.soft.fip) -#define cs_selector (I387.soft.fcs) -#define data_operand_offset (I387.soft.foo) -#define operand_selector (I387.soft.fos) +#define instruction_address (*(struct address *)&I387.soft.fip) +#define operand_address (*(struct address *)&I387.soft.foo) #define FPU_verify_area(x,y,z) if ( verify_area(x,y,z) ) \ math_abort(FPU_info,SIGSEGV) @@ -63,8 +78,5 @@ past the upper boundary of a legal code area. */ #define FPU_code_verify_area(z) FPU_verify_area(VERIFY_READ,(void *)FPU_EIP,z) #endif - -/* ######## temporary and ugly ;-) */ -#define FPU_data_address ((void *)(I387.soft.twd)) #endif diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/fpu_trig.c linux/drivers/FPU-emu/fpu_trig.c --- v1.1.17/linux/drivers/FPU-emu/fpu_trig.c Tue Jan 11 11:10:49 1994 +++ linux/drivers/FPU-emu/fpu_trig.c Thu Jun 2 10:28:26 1994 @@ -166,16 +166,16 @@ } -static void single_arg_error(void) +static void single_arg_error(FPU_REG *st0_ptr) { - switch ( FPU_st0_tag ) + switch ( st0_ptr->tag ) { case TW_NaN: - if ( !(FPU_st0_ptr->sigh & 0x40000000) ) /* Signaling ? */ + if ( !(st0_ptr->sigh & 0x40000000) ) /* Signaling ? */ { EXCEPTION(EX_Invalid); if ( control_word & CW_Invalid ) - FPU_st0_ptr->sigh |= 0x40000000; /* Convert to a QNaN */ + st0_ptr->sigh |= 0x40000000; /* Convert to a QNaN */ } break; /* return with a NaN in st(0) */ case TW_Empty: @@ -189,24 +189,24 @@ } -static void single_arg_2_error(void) +static void single_arg_2_error(FPU_REG *st0_ptr) { FPU_REG *st_new_ptr; - switch ( FPU_st0_tag ) + switch ( st0_ptr->tag ) { case TW_NaN: - if ( !(FPU_st0_ptr->sigh & 0x40000000) ) /* Signaling ? */ + if ( !(st0_ptr->sigh & 0x40000000) ) /* Signaling ? */ { EXCEPTION(EX_Invalid); if ( control_word & CW_Invalid ) { /* The masked response */ /* Convert to a QNaN */ - FPU_st0_ptr->sigh |= 0x40000000; + st0_ptr->sigh |= 0x40000000; st_new_ptr = &st(-1); push(); - reg_move(&st(1), FPU_st0_ptr); + reg_move(&st(1), st_new_ptr); } } else @@ -214,7 +214,7 @@ /* A QNaN */ st_new_ptr = &st(-1); push(); - reg_move(&st(1), FPU_st0_ptr); + reg_move(&st(1), st_new_ptr); } break; /* return with a NaN in st(0) */ #ifdef PARANOID @@ -227,48 +227,48 @@ /*---------------------------------------------------------------------------*/ -static void f2xm1(void) +static void f2xm1(FPU_REG *st0_ptr) { clear_C1(); - switch ( FPU_st0_tag ) + switch ( st0_ptr->tag ) { case TW_Valid: { FPU_REG rv, tmp; - if ( FPU_st0_ptr->exp >= 0 ) + if ( st0_ptr->exp >= 0 ) { /* For an 80486 FPU, the result is undefined. */ } - else if ( FPU_st0_ptr->exp >= -64 ) + else if ( st0_ptr->exp >= -64 ) { - if ( FPU_st0_ptr->sign == SIGN_POS ) + if ( st0_ptr->sign == SIGN_POS ) { /* poly_2xm1(x) requires 0 < x < 1. */ - poly_2xm1(FPU_st0_ptr, &rv); - reg_mul(&rv, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION); + poly_2xm1(st0_ptr, &rv); + reg_mul(&rv, st0_ptr, st0_ptr, FULL_PRECISION); } else { /* poly_2xm1(x) doesn't handle negative numbers yet. */ /* So we compute z=poly_2xm1(-x), and the answer is then -z/(1+z) */ - FPU_st0_ptr->sign = SIGN_POS; - poly_2xm1(FPU_st0_ptr, &rv); - reg_mul(&rv, FPU_st0_ptr, &rv, FULL_PRECISION); + st0_ptr->sign = SIGN_POS; + poly_2xm1(st0_ptr, &rv); + reg_mul(&rv, st0_ptr, &rv, FULL_PRECISION); reg_add(&rv, &CONST_1, &tmp, FULL_PRECISION); - reg_div(&rv, &tmp, FPU_st0_ptr, FULL_PRECISION); - FPU_st0_ptr->sign = SIGN_NEG; + reg_div(&rv, &tmp, st0_ptr, FULL_PRECISION); + st0_ptr->sign = SIGN_NEG; } } else { #ifdef DENORM_OPERAND - if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) return; #endif DENORM_OPERAND /* For very small arguments, this is accurate enough. */ - reg_mul(&CONST_LN2, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION); + reg_mul(&CONST_LN2, st0_ptr, st0_ptr, FULL_PRECISION); } set_precision_flag_up(); return; @@ -276,27 +276,28 @@ case TW_Zero: return; case TW_Infinity: - if ( FPU_st0_ptr->sign == SIGN_NEG ) + if ( st0_ptr->sign == SIGN_NEG ) { /* -infinity gives -1 (p16-10) */ - reg_move(&CONST_1, FPU_st0_ptr); - FPU_st0_ptr->sign = SIGN_NEG; + reg_move(&CONST_1, st0_ptr); + st0_ptr->sign = SIGN_NEG; } return; default: - single_arg_error(); + single_arg_error(st0_ptr); } } -static void fptan(void) +static void fptan(FPU_REG *st0_ptr) { + char st0_tag = st0_ptr->tag; FPU_REG *st_new_ptr; int q; - char arg_sign = FPU_st0_ptr->sign; + char arg_sign = st0_ptr->sign; /* Stack underflow has higher priority */ - if ( FPU_st0_tag == TW_Empty ) + if ( st0_tag == TW_Empty ) { stack_underflow(); /* Puts a QNaN in st(0) */ if ( control_word & CW_Invalid ) @@ -311,24 +312,24 @@ if ( STACK_OVERFLOW ) { stack_overflow(); return; } - switch ( FPU_st0_tag ) + switch ( st0_tag ) { case TW_Valid: - if ( FPU_st0_ptr->exp > EXP_BIAS - 40 ) + if ( st0_ptr->exp > EXP_BIAS - 40 ) { - FPU_st0_ptr->sign = SIGN_POS; - if ( (q = trig_arg(FPU_st0_ptr, FPTAN)) != -1 ) + st0_ptr->sign = SIGN_POS; + if ( (q = trig_arg(st0_ptr, FPTAN)) != -1 ) { - reg_div(FPU_st0_ptr, &CONST_PI2, FPU_st0_ptr, + reg_div(st0_ptr, &CONST_PI2, st0_ptr, FULL_PRECISION); - poly_tan(FPU_st0_ptr, FPU_st0_ptr, q & FCOS); - FPU_st0_ptr->sign = (q & 1) ^ arg_sign; + poly_tan(st0_ptr, st0_ptr, q & FCOS); + st0_ptr->sign = (q & 1) ^ arg_sign; } else { /* Operand is out of range */ - FPU_st0_ptr->sign = arg_sign; /* restore st(0) */ + st0_ptr->sign = arg_sign; /* restore st(0) */ return; } } @@ -337,7 +338,7 @@ /* For a small arg, the result == the argument */ /* Underflow may happen */ - if ( FPU_st0_ptr->exp <= EXP_UNDER ) + if ( st0_ptr->exp <= EXP_UNDER ) { #ifdef DENORM_OPERAND if ( denormal_operand() ) @@ -346,90 +347,91 @@ /* A denormal result has been produced. Precision must have been lost, this is always an underflow. */ - if ( arith_underflow(FPU_st0_ptr) ) + if ( arith_underflow(st0_ptr) ) return; } else set_precision_flag_up(); /* Must be up. */ } push(); - reg_move(&CONST_1, FPU_st0_ptr); + reg_move(&CONST_1, st_new_ptr); return; break; case TW_Infinity: /* The 80486 treats infinity as an invalid operand */ - arith_invalid(FPU_st0_ptr); + arith_invalid(st0_ptr); if ( control_word & CW_Invalid ) { st_new_ptr = &st(-1); push(); - arith_invalid(FPU_st0_ptr); + arith_invalid(st_new_ptr); } return; case TW_Zero: push(); - reg_move(&CONST_1, FPU_st0_ptr); + reg_move(&CONST_1, st_new_ptr); setcc(0); break; default: - single_arg_2_error(); + single_arg_2_error(st0_ptr); break; } } -static void fxtract(void) +static void fxtract(FPU_REG *st0_ptr) { + char st0_tag = st0_ptr->tag; FPU_REG *st_new_ptr; - register FPU_REG *st1_ptr = FPU_st0_ptr; /* anticipate */ + register FPU_REG *st1_ptr = st0_ptr; /* anticipate */ if ( STACK_OVERFLOW ) { stack_overflow(); return; } clear_C1(); - if ( !(FPU_st0_tag ^ TW_Valid) ) + if ( !(st0_tag ^ TW_Valid) ) { long e; #ifdef DENORM_OPERAND - if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) return; #endif DENORM_OPERAND push(); - reg_move(st1_ptr, FPU_st0_ptr); - FPU_st0_ptr->exp = EXP_BIAS; + reg_move(st1_ptr, st_new_ptr); + st_new_ptr->exp = EXP_BIAS; e = st1_ptr->exp - EXP_BIAS; convert_l2reg(&e, st1_ptr); return; } - else if ( FPU_st0_tag == TW_Zero ) + else if ( st0_tag == TW_Zero ) { - char sign = FPU_st0_ptr->sign; - if ( divide_by_zero(SIGN_NEG, FPU_st0_ptr) ) + char sign = st0_ptr->sign; + if ( divide_by_zero(SIGN_NEG, st0_ptr) ) return; push(); - reg_move(&CONST_Z, FPU_st0_ptr); - FPU_st0_ptr->sign = sign; + reg_move(&CONST_Z, st_new_ptr); + st_new_ptr->sign = sign; return; } - else if ( FPU_st0_tag == TW_Infinity ) + else if ( st0_tag == TW_Infinity ) { - char sign = FPU_st0_ptr->sign; - FPU_st0_ptr->sign = SIGN_POS; + char sign = st0_ptr->sign; + st0_ptr->sign = SIGN_POS; push(); - reg_move(&CONST_INF, FPU_st0_ptr); - FPU_st0_ptr->sign = sign; + reg_move(&CONST_INF, st_new_ptr); + st_new_ptr->sign = sign; return; } - else if ( FPU_st0_tag == TW_NaN ) + else if ( st0_tag == TW_NaN ) { - if ( real_2op_NaN(FPU_st0_ptr, FPU_st0_ptr, FPU_st0_ptr) ) + if ( real_2op_NaN(st0_ptr, st0_ptr, st0_ptr) ) return; push(); - reg_move(st1_ptr, FPU_st0_ptr); + reg_move(st1_ptr, st_new_ptr); return; } - else if ( FPU_st0_tag == TW_Empty ) + else if ( st0_tag == TW_Empty ) { /* Is this the correct behaviour? */ if ( control_word & EX_Invalid ) @@ -448,110 +450,114 @@ } -static void fdecstp(void) +static void fdecstp(FPU_REG *st0_ptr) { clear_C1(); - top--; /* FPU_st0_ptr will be fixed in math_emulate() before the next instr */ + top--; /* st0_ptr will be fixed in math_emulate() before the next instr */ } -static void fincstp(void) +static void fincstp(FPU_REG *st0_ptr) { clear_C1(); - top++; /* FPU_st0_ptr will be fixed in math_emulate() before the next instr */ + top++; /* st0_ptr will be fixed in math_emulate() before the next instr */ } -static void fsqrt_(void) +static void fsqrt_(FPU_REG *st0_ptr) { + char st0_tag = st0_ptr->tag; + clear_C1(); - if ( !(FPU_st0_tag ^ TW_Valid) ) + if ( !(st0_tag ^ TW_Valid) ) { int expon; - if (FPU_st0_ptr->sign == SIGN_NEG) + if (st0_ptr->sign == SIGN_NEG) { - arith_invalid(FPU_st0_ptr); /* sqrt(negative) is invalid */ + arith_invalid(st0_ptr); /* sqrt(negative) is invalid */ return; } #ifdef DENORM_OPERAND - if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) return; #endif DENORM_OPERAND - expon = FPU_st0_ptr->exp - EXP_BIAS; - FPU_st0_ptr->exp = EXP_BIAS + (expon & 1); /* make st(0) in [1.0 .. 4.0) */ + expon = st0_ptr->exp - EXP_BIAS; + st0_ptr->exp = EXP_BIAS + (expon & 1); /* make st(0) in [1.0 .. 4.0) */ - wm_sqrt(FPU_st0_ptr, control_word); /* Do the computation */ + wm_sqrt(st0_ptr, control_word); /* Do the computation */ - FPU_st0_ptr->exp += expon >> 1; - FPU_st0_ptr->sign = SIGN_POS; + st0_ptr->exp += expon >> 1; + st0_ptr->sign = SIGN_POS; } - else if ( FPU_st0_tag == TW_Zero ) + else if ( st0_tag == TW_Zero ) return; - else if ( FPU_st0_tag == TW_Infinity ) + else if ( st0_tag == TW_Infinity ) { - if ( FPU_st0_ptr->sign == SIGN_NEG ) - arith_invalid(FPU_st0_ptr); /* sqrt(-Infinity) is invalid */ + if ( st0_ptr->sign == SIGN_NEG ) + arith_invalid(st0_ptr); /* sqrt(-Infinity) is invalid */ return; } else - { single_arg_error(); return; } + { single_arg_error(st0_ptr); return; } } -static void frndint_(void) +static void frndint_(FPU_REG *st0_ptr) { + char st0_tag = st0_ptr->tag; int flags; - if ( !(FPU_st0_tag ^ TW_Valid) ) + if ( !(st0_tag ^ TW_Valid) ) { - if (FPU_st0_ptr->exp > EXP_BIAS+63) + if (st0_ptr->exp > EXP_BIAS+63) return; #ifdef DENORM_OPERAND - if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) return; #endif DENORM_OPERAND /* Fortunately, this can't overflow to 2^64 */ - if ( (flags = round_to_int(FPU_st0_ptr)) ) + if ( (flags = round_to_int(st0_ptr)) ) set_precision_flag(flags); - FPU_st0_ptr->exp = EXP_BIAS + 63; - normalize(FPU_st0_ptr); + st0_ptr->exp = EXP_BIAS + 63; + normalize(st0_ptr); return; } - else if ( (FPU_st0_tag == TW_Zero) || (FPU_st0_tag == TW_Infinity) ) + else if ( (st0_tag == TW_Zero) || (st0_tag == TW_Infinity) ) return; else - single_arg_error(); + single_arg_error(st0_ptr); } -static void fsin(void) +static void fsin(FPU_REG *st0_ptr) { - char arg_sign = FPU_st0_ptr->sign; + char st0_tag = st0_ptr->tag; + char arg_sign = st0_ptr->sign; - if ( FPU_st0_tag == TW_Valid ) + if ( st0_tag == TW_Valid ) { FPU_REG rv; int q; - if ( FPU_st0_ptr->exp > EXP_BIAS - 40 ) + if ( st0_ptr->exp > EXP_BIAS - 40 ) { - FPU_st0_ptr->sign = SIGN_POS; - if ( (q = trig_arg(FPU_st0_ptr, 0)) != -1 ) + st0_ptr->sign = SIGN_POS; + if ( (q = trig_arg(st0_ptr, 0)) != -1 ) { - reg_div(FPU_st0_ptr, &CONST_PI2, FPU_st0_ptr, FULL_PRECISION); + reg_div(st0_ptr, &CONST_PI2, st0_ptr, FULL_PRECISION); - poly_sine(FPU_st0_ptr, &rv); + poly_sine(st0_ptr, &rv); if (q & 2) rv.sign ^= SIGN_POS ^ SIGN_NEG; rv.sign ^= arg_sign; - reg_move(&rv, FPU_st0_ptr); + reg_move(&rv, st0_ptr); /* We do not really know if up or down */ set_precision_flag_up(); @@ -560,7 +566,7 @@ else { /* Operand is out of range */ - FPU_st0_ptr->sign = arg_sign; /* restore st(0) */ + st0_ptr->sign = arg_sign; /* restore st(0) */ return; } } @@ -569,7 +575,7 @@ /* For a small arg, the result == the argument */ /* Underflow may happen */ - if ( FPU_st0_ptr->exp <= EXP_UNDER ) + if ( st0_ptr->exp <= EXP_UNDER ) { #ifdef DENORM_OPERAND if ( denormal_operand() ) @@ -578,26 +584,26 @@ /* A denormal result has been produced. Precision must have been lost, this is always an underflow. */ - arith_underflow(FPU_st0_ptr); + arith_underflow(st0_ptr); return; } set_precision_flag_up(); /* Must be up. */ } } - else if ( FPU_st0_tag == TW_Zero ) + else if ( st0_tag == TW_Zero ) { setcc(0); return; } - else if ( FPU_st0_tag == TW_Infinity ) + else if ( st0_tag == TW_Infinity ) { /* The 80486 treats infinity as an invalid operand */ - arith_invalid(FPU_st0_ptr); + arith_invalid(st0_ptr); return; } else - single_arg_error(); + single_arg_error(st0_ptr); } @@ -658,33 +664,34 @@ setcc(0); return 0; } - else if ( FPU_st0_tag == TW_Infinity ) + else if ( arg->tag == TW_Infinity ) { /* The 80486 treats infinity as an invalid operand */ - arith_invalid(FPU_st0_ptr); + arith_invalid(arg); return 1; } else { - single_arg_error(); /* requires arg == &st(0) */ + single_arg_error(arg); /* requires arg == &st(0) */ return 1; } } -static void fcos(void) +static void fcos(FPU_REG *st0_ptr) { - f_cos(FPU_st0_ptr); + f_cos(st0_ptr); } -static void fsincos(void) +static void fsincos(FPU_REG *st0_ptr) { + char st0_tag = st0_ptr->tag; FPU_REG *st_new_ptr; FPU_REG arg; /* Stack underflow has higher priority */ - if ( FPU_st0_tag == TW_Empty ) + if ( st0_tag == TW_Empty ) { stack_underflow(); /* Puts a QNaN in st(0) */ if ( control_word & CW_Invalid ) @@ -699,29 +706,29 @@ if ( STACK_OVERFLOW ) { stack_overflow(); return; } - if ( FPU_st0_tag == TW_NaN ) + if ( st0_tag == TW_NaN ) { - single_arg_2_error(); + single_arg_2_error(st0_ptr); return; } - else if ( FPU_st0_tag == TW_Infinity ) + else if ( st0_tag == TW_Infinity ) { /* The 80486 treats infinity as an invalid operand */ - if ( !arith_invalid(FPU_st0_ptr) ) + if ( !arith_invalid(st0_ptr) ) { /* unmasked response */ push(); - arith_invalid(FPU_st0_ptr); + arith_invalid(st_new_ptr); } return; } - reg_move(FPU_st0_ptr,&arg); + reg_move(st0_ptr,&arg); if ( !f_cos(&arg) ) { - fsin(); + fsin(st0_ptr); push(); - reg_move(&arg,FPU_st0_ptr); + reg_move(&arg,st_new_ptr); } } @@ -760,23 +767,24 @@ /* Remainder of st(0) / st(1) */ /* This routine produces exact results, i.e. there is never any rounding or truncation, etc of the result. */ -static void do_fprem(int round) +static void do_fprem(FPU_REG *st0_ptr, int round) { FPU_REG *st1_ptr = &st(1); char st1_tag = st1_ptr->tag; - char sign = FPU_st0_ptr->sign; + char st0_tag = st0_ptr->tag; + char sign = st0_ptr->sign; - if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) ) + if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) ) { FPU_REG tmp; int old_cw = control_word; - int expdif = FPU_st0_ptr->exp - st1_ptr->exp; + int expdif = st0_ptr->exp - st1_ptr->exp; long long q; unsigned short saved_status; int cc = 0; #ifdef DENORM_OPERAND - if ( ((FPU_st0_ptr->exp <= EXP_UNDER) || + if ( ((st0_ptr->exp <= EXP_UNDER) || (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) ) return; #endif DENORM_OPERAND @@ -793,7 +801,7 @@ if ( expdif > -2 ) { - reg_div(FPU_st0_ptr, st1_ptr, &tmp, PR_64_BITS | RC_CHOP | 0x3f); + reg_div(st0_ptr, st1_ptr, &tmp, PR_64_BITS | RC_CHOP | 0x3f); if ( tmp.exp >= EXP_BIAS ) { @@ -801,7 +809,7 @@ to 2^64 */ q = significand(&tmp); - rem_kernel(significand(FPU_st0_ptr), + rem_kernel(significand(st0_ptr), &significand(&tmp), significand(st1_ptr), q, expdif); @@ -810,7 +818,7 @@ } else { - reg_move(FPU_st0_ptr, &tmp); + reg_move(st0_ptr, &tmp); q = 0; } tmp.sign = sign; @@ -858,7 +866,7 @@ /* prevent overflow here */ /* N is 'a number between 32 and 63' (p26-113) */ - reg_move(FPU_st0_ptr, &tmp); + reg_move(st0_ptr, &tmp); tmp.exp = EXP_BIAS + 56; exp_1 = st1_ptr->exp; st1_ptr->exp = EXP_BIAS; expdif -= 56; @@ -868,7 +876,7 @@ round_to_int(&tmp); /* Fortunately, this can't overflow to 2^64 */ - rem_kernel(significand(FPU_st0_ptr), + rem_kernel(significand(st0_ptr), &significand(&tmp), significand(st1_ptr), significand(&tmp), @@ -887,8 +895,8 @@ /* The result is zero */ control_word = old_cw; partial_status = saved_status; - reg_move(&CONST_Z, FPU_st0_ptr); - FPU_st0_ptr->sign = sign; + reg_move(&CONST_Z, st0_ptr); + st0_ptr->sign = sign; #ifdef PECULIAR_486 setcc(SW_C2); #else @@ -902,23 +910,23 @@ control_word = old_cw; partial_status = saved_status; normalize_nuo(&tmp); - reg_move(&tmp, FPU_st0_ptr); + reg_move(&tmp, st0_ptr); setcc(cc); /* The only condition to be looked for is underflow, and it can occur here only if underflow is unmasked. */ - if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (FPU_st0_ptr->tag != TW_Zero) + if ( (st0_ptr->exp <= EXP_UNDER) && (st0_ptr->tag != TW_Zero) && !(control_word & CW_Underflow) ) - arith_underflow(FPU_st0_ptr); + arith_underflow(st0_ptr); return; } - else if ( (FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty) ) + else if ( (st0_tag == TW_Empty) | (st1_tag == TW_Empty) ) { stack_underflow(); return; } - else if ( FPU_st0_tag == TW_Zero ) + else if ( st0_tag == TW_Zero ) { if ( st1_tag == TW_Valid ) { @@ -930,21 +938,21 @@ setcc(0); return; } else if ( st1_tag == TW_Zero ) - { arith_invalid(FPU_st0_ptr); return; } /* fprem(?,0) always invalid */ + { arith_invalid(st0_ptr); return; } /* fprem(?,0) always invalid */ else if ( st1_tag == TW_Infinity ) { setcc(0); return; } } - else if ( FPU_st0_tag == TW_Valid ) + else if ( st0_tag == TW_Valid ) { if ( st1_tag == TW_Zero ) { - arith_invalid(FPU_st0_ptr); /* fprem(Valid,Zero) is invalid */ + arith_invalid(st0_ptr); /* fprem(Valid,Zero) is invalid */ return; } else if ( st1_tag != TW_NaN ) { #ifdef DENORM_OPERAND - if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) return; #endif DENORM_OPERAND @@ -955,11 +963,11 @@ } } } - else if ( FPU_st0_tag == TW_Infinity ) + else if ( st0_tag == TW_Infinity ) { if ( st1_tag != TW_NaN ) { - arith_invalid(FPU_st0_ptr); /* fprem(Infinity,?) is invalid */ + arith_invalid(st0_ptr); /* fprem(Infinity,?) is invalid */ return; } } @@ -967,30 +975,31 @@ /* One of the registers must contain a NaN is we got here. */ #ifdef PARANOID - if ( (FPU_st0_tag != TW_NaN) && (st1_tag != TW_NaN) ) + if ( (st0_tag != TW_NaN) && (st1_tag != TW_NaN) ) EXCEPTION(EX_INTERNAL | 0x118); #endif PARANOID - real_2op_NaN(st1_ptr, FPU_st0_ptr, FPU_st0_ptr); + real_2op_NaN(st1_ptr, st0_ptr, st0_ptr); } /* ST(1) <- ST(1) * log ST; pop ST */ -static void fyl2x(void) +static void fyl2x(FPU_REG *st0_ptr) { + char st0_tag = st0_ptr->tag; FPU_REG *st1_ptr = &st(1); char st1_tag = st1_ptr->tag; clear_C1(); - if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) ) + if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) ) { - if ( FPU_st0_ptr->sign == SIGN_POS ) + if ( st0_ptr->sign == SIGN_POS ) { int saved_control, saved_status; #ifdef DENORM_OPERAND - if ( ((FPU_st0_ptr->exp <= EXP_UNDER) || + if ( ((st0_ptr->exp <= EXP_UNDER) || (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) ) return; #endif DENORM_OPERAND @@ -1001,16 +1010,16 @@ saved_control = control_word; control_word = FULL_PRECISION; - poly_l2(FPU_st0_ptr, FPU_st0_ptr); + poly_l2(st0_ptr, st0_ptr); /* Enough of the basic arithmetic is done now */ control_word = saved_control; partial_status = saved_status; /* Let the multiply set the flags */ - reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION); + reg_mul(st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION); - pop(); FPU_st0_ptr = &st(0); + pop(); } else { @@ -1020,21 +1029,21 @@ return; } } - else if ( (FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty) ) + else if ( (st0_tag == TW_Empty) || (st1_tag == TW_Empty) ) { stack_underflow_pop(1); return; } - else if ( (FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN) ) + else if ( (st0_tag == TW_NaN) || (st1_tag == TW_NaN) ) { - if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) ) + if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) ) pop(); return; } - else if ( (FPU_st0_tag <= TW_Zero) && (st1_tag <= TW_Zero) ) + else if ( (st0_tag <= TW_Zero) && (st1_tag <= TW_Zero) ) { /* one of the args is zero, the other valid, or both zero */ - if ( FPU_st0_tag == TW_Zero ) + if ( st0_tag == TW_Zero ) { if ( st1_tag == TW_Zero ) { @@ -1046,7 +1055,7 @@ /* This case is not specifically covered in the manual, but divide-by-zero would seem to be the best response. However, a real 80486 does it this way... */ - else if ( FPU_st0_ptr->tag == TW_Infinity ) + else if ( st0_ptr->tag == TW_Infinity ) { reg_move(&CONST_INF, st1_ptr); pop(); @@ -1065,7 +1074,7 @@ /* Zero is the valid answer */ char sign = st1_ptr->sign; - if ( FPU_st0_ptr->sign == SIGN_NEG ) + if ( st0_ptr->sign == SIGN_NEG ) { /* log(negative) */ if ( !arith_invalid(st1_ptr) ) @@ -1074,21 +1083,21 @@ } #ifdef DENORM_OPERAND - if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) return; #endif DENORM_OPERAND - if ( FPU_st0_ptr->exp < EXP_BIAS ) sign ^= SIGN_NEG^SIGN_POS; - pop(); FPU_st0_ptr = &st(0); - reg_move(&CONST_Z, FPU_st0_ptr); - FPU_st0_ptr->sign = sign; + if ( st0_ptr->exp < EXP_BIAS ) sign ^= SIGN_NEG^SIGN_POS; + pop(); st0_ptr = &st(0); + reg_move(&CONST_Z, st0_ptr); + st0_ptr->sign = sign; return; } } /* One or both arg must be an infinity */ - else if ( FPU_st0_tag == TW_Infinity ) + else if ( st0_tag == TW_Infinity ) { - if ( (FPU_st0_ptr->sign == SIGN_NEG) || (st1_tag == TW_Zero) ) + if ( (st0_ptr->sign == SIGN_NEG) || (st1_tag == TW_Zero) ) { /* log(-infinity) or 0*log(infinity) */ if ( !arith_invalid(st1_ptr) ) @@ -1104,20 +1113,20 @@ return; #endif DENORM_OPERAND - pop(); FPU_st0_ptr = &st(0); - reg_move(&CONST_INF, FPU_st0_ptr); - FPU_st0_ptr->sign = sign; + pop(); st0_ptr = &st(0); + reg_move(&CONST_INF, st0_ptr); + st0_ptr->sign = sign; return; } } /* st(1) must be infinity here */ - else if ( (FPU_st0_tag == TW_Valid) && (FPU_st0_ptr->sign == SIGN_POS) ) + else if ( (st0_tag == TW_Valid) && (st0_ptr->sign == SIGN_POS) ) { - if ( FPU_st0_ptr->exp >= EXP_BIAS ) + if ( st0_ptr->exp >= EXP_BIAS ) { - if ( (FPU_st0_ptr->exp == EXP_BIAS) && - (FPU_st0_ptr->sigh == 0x80000000) && - (FPU_st0_ptr->sigl == 0) ) + if ( (st0_ptr->exp == EXP_BIAS) && + (st0_ptr->sigh == 0x80000000) && + (st0_ptr->sigl == 0) ) { /* st(0) holds 1.0 */ /* infinity*log(1) */ @@ -1133,7 +1142,7 @@ /* st(0) is positive and < 1.0 */ #ifdef DENORM_OPERAND - if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) return; #endif DENORM_OPERAND @@ -1145,7 +1154,7 @@ else { /* st(0) must be zero or negative */ - if ( FPU_st0_ptr->tag == TW_Zero ) + if ( st0_ptr->tag == TW_Zero ) { /* This should be invalid, but a real 80486 is happy with it. */ #ifndef PECULIAR_486 @@ -1167,21 +1176,22 @@ } -static void fpatan(void) +static void fpatan(FPU_REG *st0_ptr) { + char st0_tag = st0_ptr->tag; FPU_REG *st1_ptr = &st(1); char st1_tag = st1_ptr->tag; - char st1_sign = st1_ptr->sign, st0_sign = FPU_st0_ptr->sign; + char st1_sign = st1_ptr->sign, st0_sign = st0_ptr->sign; clear_C1(); - if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) ) + if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) ) { int saved_control, saved_status; FPU_REG sum; char inverted; #ifdef DENORM_OPERAND - if ( ((FPU_st0_ptr->exp <= EXP_UNDER) || + if ( ((st0_ptr->exp <= EXP_UNDER) || (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) ) return; #endif DENORM_OPERAND @@ -1191,28 +1201,28 @@ saved_control = control_word; control_word = FULL_PRECISION; - st1_ptr->sign = FPU_st0_ptr->sign = SIGN_POS; + st1_ptr->sign = st0_ptr->sign = SIGN_POS; if ( (compare(st1_ptr) & ~COMP_Denormal) == COMP_A_lt_B ) { inverted = 1; - reg_div(FPU_st0_ptr, st1_ptr, &sum, FULL_PRECISION); + reg_div(st0_ptr, st1_ptr, &sum, FULL_PRECISION); } else { inverted = 0; if ( (st0_sign == 0) && - (st1_ptr->exp - FPU_st0_ptr->exp < -64) ) + (st1_ptr->exp - st0_ptr->exp < -64) ) { control_word = saved_control; partial_status = saved_status; - reg_div(st1_ptr, FPU_st0_ptr, st1_ptr, + reg_div(st1_ptr, st0_ptr, st1_ptr, control_word | PR_64_BITS); st1_ptr->sign = st1_sign; pop(); set_precision_flag_down(); return; } - reg_div(st1_ptr, FPU_st0_ptr, &sum, FULL_PRECISION); + reg_div(st1_ptr, st0_ptr, &sum, FULL_PRECISION); } poly_atan(&sum); @@ -1233,25 +1243,25 @@ reg_move(&sum, st1_ptr); } - else if ( (FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty) ) + else if ( (st0_tag == TW_Empty) || (st1_tag == TW_Empty) ) { stack_underflow_pop(1); return; } - else if ( (FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN) ) + else if ( (st0_tag == TW_NaN) || (st1_tag == TW_NaN) ) { - if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) ) + if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) ) pop(); return; } - else if ( (FPU_st0_tag == TW_Infinity) || (st1_tag == TW_Infinity) ) + else if ( (st0_tag == TW_Infinity) || (st1_tag == TW_Infinity) ) { char sign = st1_ptr->sign; - if ( FPU_st0_tag == TW_Infinity ) + if ( st0_tag == TW_Infinity ) { if ( st1_tag == TW_Infinity ) { - if ( FPU_st0_ptr->sign == SIGN_POS ) + if ( st0_ptr->sign == SIGN_POS ) { reg_move(&CONST_PI4, st1_ptr); } else reg_add(&CONST_PI4, &CONST_PI2, st1_ptr, FULL_PRECISION); @@ -1266,7 +1276,7 @@ } #endif DENORM_OPERAND - if ( FPU_st0_ptr->sign == SIGN_POS ) + if ( st0_ptr->sign == SIGN_POS ) { reg_move(&CONST_Z, st1_ptr); st1_ptr->sign = sign; /* An 80486 preserves the sign */ @@ -1281,9 +1291,9 @@ { /* st(1) is infinity, st(0) not infinity */ #ifdef DENORM_OPERAND - if ( FPU_st0_tag != TW_Zero ) + if ( st0_tag != TW_Zero ) { - if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) return; } #endif DENORM_OPERAND @@ -1298,20 +1308,20 @@ char sign = st1_ptr->sign; #ifdef DENORM_OPERAND - if ( FPU_st0_tag != TW_Zero ) + if ( st0_tag != TW_Zero ) { - if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) return; } #endif DENORM_OPERAND - if ( FPU_st0_ptr->sign == SIGN_POS ) + if ( st0_ptr->sign == SIGN_POS ) { /* An 80486 preserves the sign */ pop(); return; } else reg_move(&CONST_PI, st1_ptr); st1_ptr->sign = sign; } - else if ( FPU_st0_tag == TW_Zero ) + else if ( st0_tag == TW_Zero ) { /* st(1) must be TW_Valid here */ char sign = st1_ptr->sign; @@ -1334,30 +1344,31 @@ } -static void fprem(void) +static void fprem(FPU_REG *st0_ptr) { - do_fprem(RC_CHOP); + do_fprem(st0_ptr, RC_CHOP); } -static void fprem1(void) +static void fprem1(FPU_REG *st0_ptr) { - do_fprem(RC_RND); + do_fprem(st0_ptr, RC_RND); } -static void fyl2xp1(void) +static void fyl2xp1(FPU_REG *st0_ptr) { + char st0_tag = st0_ptr->tag; FPU_REG *st1_ptr = &st(1); char st1_tag = st1_ptr->tag; clear_C1(); - if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) ) + if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) ) { int saved_control, saved_status; #ifdef DENORM_OPERAND - if ( ((FPU_st0_ptr->exp <= EXP_UNDER) || + if ( ((st0_ptr->exp <= EXP_UNDER) || (st1_ptr->exp <= EXP_UNDER)) && denormal_operand() ) return; #endif DENORM_OPERAND @@ -1367,7 +1378,7 @@ saved_control = control_word; control_word = FULL_PRECISION; - if ( poly_l2p1(FPU_st0_ptr, FPU_st0_ptr) ) + if ( poly_l2p1(st0_ptr, st0_ptr) ) { #ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */ st1_ptr->sign ^= SIGN_POS^SIGN_NEG; @@ -1386,16 +1397,16 @@ partial_status = saved_status; /* Let the multiply set the flags */ - reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION); + reg_mul(st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION); pop(); } - else if ( (FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty) ) + else if ( (st0_tag == TW_Empty) | (st1_tag == TW_Empty) ) { stack_underflow_pop(1); return; } - else if ( FPU_st0_tag == TW_Zero ) + else if ( st0_tag == TW_Zero ) { if ( st1_tag <= TW_Zero ) { @@ -1405,8 +1416,8 @@ return; #endif DENORM_OPERAND - FPU_st0_ptr->sign ^= st1_ptr->sign; - reg_move(FPU_st0_ptr, st1_ptr); + st0_ptr->sign ^= st1_ptr->sign; + reg_move(st0_ptr, st1_ptr); } else if ( st1_tag == TW_Infinity ) { @@ -1417,7 +1428,7 @@ } else if ( st1_tag == TW_NaN ) { - if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) ) + if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) ) pop(); return; } @@ -1430,13 +1441,13 @@ #endif PARANOID pop(); return; } - else if ( FPU_st0_tag == TW_Valid ) + else if ( st0_tag == TW_Valid ) { if ( st1_tag == TW_Zero ) { - if ( FPU_st0_ptr->sign == SIGN_NEG ) + if ( st0_ptr->sign == SIGN_NEG ) { - if ( FPU_st0_ptr->exp >= EXP_BIAS ) + if ( st0_ptr->exp >= EXP_BIAS ) { /* st(0) holds <= -1.0 */ #ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */ @@ -1447,25 +1458,25 @@ pop(); return; } #ifdef DENORM_OPERAND - if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) return; #endif DENORM_OPERAND st1_ptr->sign ^= SIGN_POS^SIGN_NEG; pop(); return; } #ifdef DENORM_OPERAND - if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) return; #endif DENORM_OPERAND pop(); return; } if ( st1_tag == TW_Infinity ) { - if ( FPU_st0_ptr->sign == SIGN_NEG ) + if ( st0_ptr->sign == SIGN_NEG ) { - if ( (FPU_st0_ptr->exp >= EXP_BIAS) && - !((FPU_st0_ptr->sigh == 0x80000000) && - (FPU_st0_ptr->sigl == 0)) ) + if ( (st0_ptr->exp >= EXP_BIAS) && + !((st0_ptr->sigh == 0x80000000) && + (st0_ptr->sigl == 0)) ) { /* st(0) holds < -1.0 */ #ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */ @@ -1476,40 +1487,40 @@ pop(); return; } #ifdef DENORM_OPERAND - if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) return; #endif DENORM_OPERAND st1_ptr->sign ^= SIGN_POS^SIGN_NEG; pop(); return; } #ifdef DENORM_OPERAND - if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) return; #endif DENORM_OPERAND pop(); return; } if ( st1_tag == TW_NaN ) { - if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) ) + if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) ) pop(); return; } } - else if ( FPU_st0_tag == TW_NaN ) + else if ( st0_tag == TW_NaN ) { - if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) ) + if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) ) pop(); return; } - else if ( FPU_st0_tag == TW_Infinity ) + else if ( st0_tag == TW_Infinity ) { if ( st1_tag == TW_NaN ) { - if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) ) + if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) ) pop(); return; } - else if ( FPU_st0_ptr->sign == SIGN_NEG ) + else if ( st0_ptr->sign == SIGN_NEG ) { int exponent = st1_ptr->exp; #ifndef PECULIAR_486 @@ -1565,21 +1576,22 @@ } -static void fscale(void) +static void fscale(FPU_REG *st0_ptr) { + char st0_tag = st0_ptr->tag; FPU_REG *st1_ptr = &st(1); char st1_tag = st1_ptr->tag; int old_cw = control_word; - char sign = FPU_st0_ptr->sign; + char sign = st0_ptr->sign; clear_C1(); - if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) ) + if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) ) { long scale; FPU_REG tmp; #ifdef DENORM_OPERAND - if ( ((FPU_st0_ptr->exp <= EXP_UNDER) || + if ( ((st0_ptr->exp <= EXP_UNDER) || (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) ) return; #endif DENORM_OPERAND @@ -1592,16 +1604,16 @@ if ( st1_ptr->sign == SIGN_POS ) { EXCEPTION(EX_Overflow); - sign = FPU_st0_ptr->sign; - reg_move(&CONST_INF, FPU_st0_ptr); - FPU_st0_ptr->sign = sign; + sign = st0_ptr->sign; + reg_move(&CONST_INF, st0_ptr); + st0_ptr->sign = sign; } else { EXCEPTION(EX_Underflow); - sign = FPU_st0_ptr->sign; - reg_move(&CONST_Z, FPU_st0_ptr); - FPU_st0_ptr->sign = sign; + sign = st0_ptr->sign; + reg_move(&CONST_Z, st0_ptr); + st0_ptr->sign = sign; } return; } @@ -1612,21 +1624,21 @@ round_to_int(&tmp); /* This can never overflow here */ control_word = old_cw; scale = st1_ptr->sign ? -tmp.sigl : tmp.sigl; - scale += FPU_st0_ptr->exp; - FPU_st0_ptr->exp = scale; + scale += st0_ptr->exp; + st0_ptr->exp = scale; /* Use round_reg() to properly detect under/overflow etc */ - round_reg(FPU_st0_ptr, 0, control_word); + round_reg(st0_ptr, 0, control_word); return; } - else if ( FPU_st0_tag == TW_Valid ) + else if ( st0_tag == TW_Valid ) { if ( st1_tag == TW_Zero ) { #ifdef DENORM_OPERAND - if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) return; #endif DENORM_OPERAND @@ -1635,21 +1647,21 @@ if ( st1_tag == TW_Infinity ) { #ifdef DENORM_OPERAND - if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) return; #endif DENORM_OPERAND if ( st1_ptr->sign == SIGN_POS ) - { reg_move(&CONST_INF, FPU_st0_ptr); } + { reg_move(&CONST_INF, st0_ptr); } else - reg_move(&CONST_Z, FPU_st0_ptr); - FPU_st0_ptr->sign = sign; + reg_move(&CONST_Z, st0_ptr); + st0_ptr->sign = sign; return; } if ( st1_tag == TW_NaN ) - { real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; } + { real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; } } - else if ( FPU_st0_tag == TW_Zero ) + else if ( st0_tag == TW_Zero ) { if ( st1_tag == TW_Valid ) { @@ -1668,14 +1680,14 @@ return; else { - arith_invalid(FPU_st0_ptr); /* Zero scaled by +Infinity */ + arith_invalid(st0_ptr); /* Zero scaled by +Infinity */ return; } } else if ( st1_tag == TW_NaN ) - { real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; } + { real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; } } - else if ( FPU_st0_tag == TW_Infinity ) + else if ( st0_tag == TW_Infinity ) { if ( st1_tag == TW_Valid ) { @@ -1692,20 +1704,20 @@ return; else if ( st1_tag == TW_Infinity ) { - arith_invalid(FPU_st0_ptr); /* Infinity scaled by -Infinity */ + arith_invalid(st0_ptr); /* Infinity scaled by -Infinity */ return; } else if ( st1_tag == TW_NaN ) - { real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; } + { real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; } } - else if ( FPU_st0_tag == TW_NaN ) + else if ( st0_tag == TW_NaN ) { if ( st1_tag != TW_Empty ) - { real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; } + { real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; } } #ifdef PARANOID - if ( !((FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty)) ) + if ( !((st0_tag == TW_Empty) || (st1_tag == TW_Empty)) ) { EXCEPTION(EX_INTERNAL | 0x115); return; @@ -1720,22 +1732,22 @@ /*---------------------------------------------------------------------------*/ -static FUNC const trig_table_a[] = { +static FUNC_ST0 const trig_table_a[] = { f2xm1, fyl2x, fptan, fpatan, fxtract, fprem1, fdecstp, fincstp }; void trig_a(void) { - (trig_table_a[FPU_rm])(); + (trig_table_a[FPU_rm])(&st(0)); } -static FUNC const trig_table_b[] = +static FUNC_ST0 const trig_table_b[] = { fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, fsin, fcos }; void trig_b(void) { - (trig_table_b[FPU_rm])(); + (trig_table_b[FPU_rm])(&st(0)); } diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/get_address.c linux/drivers/FPU-emu/get_address.c --- v1.1.17/linux/drivers/FPU-emu/get_address.c Tue May 24 00:34:46 1994 +++ linux/drivers/FPU-emu/get_address.c Thu Jun 2 10:28:26 1994 @@ -19,6 +19,7 @@ #include +#include #include @@ -26,6 +27,9 @@ #include "exception.h" #include "fpu_emu.h" + +#define FPU_WRITE_BIT 0x10 + static int reg_offset[] = { offsetof(struct info,___eax), offsetof(struct info,___ecx), @@ -52,7 +56,7 @@ #define VM86_REG_(x) (*(unsigned short *) \ (reg_offset_vm86[((unsigned)x)]+(char *) FPU_info)) -static int reg_offset_p286[] = { +static int reg_offset_pm[] = { offsetof(struct info,___cs), offsetof(struct info,___ds), offsetof(struct info,___es), @@ -62,12 +66,12 @@ offsetof(struct info,___ds) }; -#define P286_REG_(x) (*(unsigned short *) \ - (reg_offset_p286[((unsigned)x)]+(char *) FPU_info)) +#define PM_REG_(x) (*(unsigned short *) \ + (reg_offset_pm[((unsigned)x)]+(char *) FPU_info)) /* Decode the SIB byte. This function assumes mod != 0 */ -static void *sib(int mod, unsigned long *fpu_eip) +static int sib(int mod, unsigned long *fpu_eip) { unsigned char ss,index,base; long offset; @@ -117,14 +121,14 @@ (*fpu_eip) += 4; } - return (void *) offset; + return offset; } -static unsigned long mode16_segment(fpu_addr_modes addr_modes) +static unsigned long vm86_segment(unsigned char segment, + unsigned short *selector) { - int segment = addr_modes.override.segment - 1; - + segment--; #ifdef PARANOID if ( segment > PREFIX_SS_ ) { @@ -132,11 +136,61 @@ math_abort(FPU_info,SIGSEGV); } #endif PARANOID - if ( addr_modes.vm86 ) - return (unsigned long)VM86_REG_(segment) << 4; - else if ( addr_modes.p286 ) - return (unsigned long)LDT_BASE_ADDR(P286_REG_(segment)); - return 0; + *selector = VM86_REG_(segment); + return (unsigned long)VM86_REG_(segment) << 4; +} + + +/* This should work for 16 and 32 bit protected mode. */ +static long pm_address(unsigned char FPU_modrm, unsigned char segment, + unsigned short *selector, long offset) +{ + struct desc_struct descriptor; + unsigned long base_address, limit, address, seg_top; + + segment--; +#ifdef PARANOID + if ( segment > PREFIX_SS_ ) + { + EXCEPTION(EX_INTERNAL|0x132); + math_abort(FPU_info,SIGSEGV); + } +#endif PARANOID + + *selector = PM_REG_(segment); + + descriptor = LDT_DESCRIPTOR(PM_REG_(segment)); + base_address = SEG_BASE_ADDR(descriptor); + address = base_address + offset; + limit = base_address + + (SEG_LIMIT(descriptor)+1) * SEG_GRANULARITY(descriptor) - 1; + if ( limit < base_address ) limit = 0xffffffff; + + if ( SEG_EXPAND_DOWN(descriptor) ) + { + if ( SEG_G_BIT(descriptor) ) + seg_top = 0xffffffff; + else + { + seg_top = base_address + (1 << 20); + if ( seg_top < base_address ) seg_top = 0xffffffff; + } + access_limit = + (address <= limit) || (address >= seg_top) ? 0 : + ((seg_top-address) >= 255 ? 255 : seg_top-address); + } + else + { + access_limit = + (address > limit) || (address < base_address) ? 0 : + ((limit-address) >= 254 ? 255 : limit-address+1); + } + if ( SEG_EXECUTE_ONLY(descriptor) || + (!SEG_WRITE_PERM(descriptor) && (FPU_modrm & FPU_WRITE_BIT)) ) + { + access_limit = 0; + } + return address; } @@ -157,117 +211,132 @@ */ -void get_address(unsigned char FPU_modrm, unsigned long *fpu_eip, - fpu_addr_modes addr_modes) +void *get_address(unsigned char FPU_modrm, unsigned long *fpu_eip, + struct address *addr, +/* unsigned short *selector, unsigned long *offset, */ + fpu_addr_modes addr_modes) { unsigned char mod; + unsigned rm = FPU_modrm & 7; long *cpu_reg_ptr; - int offset = 0; /* Initialized just to stop compiler warnings. */ - -#ifndef PECULIAR_486 - /* This is a reasonable place to do this */ - FPU_data_selector = FPU_DS; -#endif PECULIAR_486 + int address = 0; /* Initialized just to stop compiler warnings. */ /* Memory accessed via the cs selector is write protected - in protected mode. */ -#define FPU_WRITE_BIT 0x10 - if ( !addr_modes.vm86 && (FPU_modrm & FPU_WRITE_BIT) + in `non-segmented' 32 bit protected mode. */ + if ( !addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT) && (addr_modes.override.segment == PREFIX_CS_) ) { math_abort(FPU_info,SIGSEGV); } + addr->selector = FPU_DS; /* Default, for 32 bit non-segmented mode. */ + mod = (FPU_modrm >> 6) & 3; - if (FPU_rm == 4 && mod != 3) + if (rm == 4 && mod != 3) { - FPU_data_address = sib(mod, fpu_eip); - return; + address = sib(mod, fpu_eip); } - - cpu_reg_ptr = & REG_(FPU_rm); - switch (mod) + else { - case 0: - if (FPU_rm == 5) + cpu_reg_ptr = & REG_(rm); + switch (mod) { - /* Special case: disp32 */ + case 0: + if (rm == 5) + { + /* Special case: disp32 */ + RE_ENTRANT_CHECK_OFF; + FPU_code_verify_area(4); + address = get_fs_long((unsigned long *) (*fpu_eip)); + (*fpu_eip) += 4; + RE_ENTRANT_CHECK_ON; + addr->offset = address; + return (void *) address; + } + else + { + address = *cpu_reg_ptr; /* Just return the contents + of the cpu register */ + addr->offset = address; + return (void *) address; + } + case 1: + /* 8 bit signed displacement */ RE_ENTRANT_CHECK_OFF; + FPU_code_verify_area(1); + address = (signed char) get_fs_byte((char *) (*fpu_eip)); + RE_ENTRANT_CHECK_ON; + (*fpu_eip)++; + break; + case 2: + /* 32 bit displacement */ + RE_ENTRANT_CHECK_OFF; FPU_code_verify_area(4); - offset = get_fs_long((unsigned long *) (*fpu_eip)); + address = (signed) get_fs_long((unsigned long *) (*fpu_eip)); (*fpu_eip) += 4; RE_ENTRANT_CHECK_ON; - FPU_data_address = (void *) offset; - return; - } - else - { - FPU_data_address = (void *)*cpu_reg_ptr; /* Just return the contents - of the cpu register */ - return; + break; + case 3: + /* Not legal for the FPU */ + EXCEPTION(EX_Invalid); } - case 1: - /* 8 bit signed displacement */ - RE_ENTRANT_CHECK_OFF; - FPU_code_verify_area(1); - offset = (signed char) get_fs_byte((char *) (*fpu_eip)); - RE_ENTRANT_CHECK_ON; - (*fpu_eip)++; - break; - case 2: - /* 32 bit displacement */ - RE_ENTRANT_CHECK_OFF; - FPU_code_verify_area(4); - offset = (signed) get_fs_long((unsigned long *) (*fpu_eip)); - (*fpu_eip) += 4; - RE_ENTRANT_CHECK_ON; - break; - case 3: - /* Not legal for the FPU */ - EXCEPTION(EX_Invalid); + address += *cpu_reg_ptr; } - if ( addr_modes.mode16 ) + addr->offset = address; + + switch ( addr_modes.default_mode ) { - offset += mode16_segment(addr_modes); + case 0: + break; + case VM86: + address += vm86_segment(addr_modes.override.segment, + (unsigned short *)&(addr->selector)); + break; + case PM16: + case SEG32: + address = pm_address(FPU_modrm, addr_modes.override.segment, + (unsigned short *)&(addr->selector), address); + break; + default: + EXCEPTION(EX_INTERNAL|0x133); } - FPU_data_address = offset + (char *)*cpu_reg_ptr; + return (void *)address; } -void get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip, - fpu_addr_modes addr_modes) +void *get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip, + struct address *addr, +/* unsigned short *selector, unsigned long *offset, */ + fpu_addr_modes addr_modes) { unsigned char mod; - int offset = 0; /* Default used for mod == 0 */ + unsigned rm = FPU_modrm & 7; + int address = 0; /* Default used for mod == 0 */ -#ifndef PECULIAR_486 - /* This is a reasonable place to do this */ - FPU_data_selector = FPU_DS; -#endif PECULIAR_486 - /* Memory accessed via the cs selector is write protected - in protected mode. */ -#define FPU_WRITE_BIT 0x10 - if ( !addr_modes.vm86 && (FPU_modrm & FPU_WRITE_BIT) + in `non-segmented' 32 bit protected mode. */ + if ( !addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT) && (addr_modes.override.segment == PREFIX_CS_) ) { math_abort(FPU_info,SIGSEGV); } + addr->selector = FPU_DS; /* Default, for 32 bit non-segmented mode. */ + mod = (FPU_modrm >> 6) & 3; switch (mod) { case 0: - if (FPU_rm == 6) + if (rm == 6) { /* Special case: disp16 */ RE_ENTRANT_CHECK_OFF; FPU_code_verify_area(2); - offset = (unsigned short)get_fs_word((unsigned short *) (*fpu_eip)); + address = (unsigned short)get_fs_word((unsigned short *) (*fpu_eip)); (*fpu_eip) += 2; RE_ENTRANT_CHECK_ON; goto add_segment; @@ -277,7 +346,7 @@ /* 8 bit signed displacement */ RE_ENTRANT_CHECK_OFF; FPU_code_verify_area(1); - offset = (signed char) get_fs_byte((signed char *) (*fpu_eip)); + address = (signed char) get_fs_byte((signed char *) (*fpu_eip)); RE_ENTRANT_CHECK_ON; (*fpu_eip)++; break; @@ -285,7 +354,7 @@ /* 16 bit displacement */ RE_ENTRANT_CHECK_OFF; FPU_code_verify_area(2); - offset = (unsigned) get_fs_word((unsigned short *) (*fpu_eip)); + address = (unsigned) get_fs_word((unsigned short *) (*fpu_eip)); (*fpu_eip) += 2; RE_ENTRANT_CHECK_ON; break; @@ -294,47 +363,61 @@ EXCEPTION(EX_Invalid); break; } - switch ( FPU_rm ) + switch ( rm ) { case 0: - offset += FPU_info->___ebx + FPU_info->___esi; + address += FPU_info->___ebx + FPU_info->___esi; break; case 1: - offset += FPU_info->___ebx + FPU_info->___edi; + address += FPU_info->___ebx + FPU_info->___edi; break; case 2: - offset += FPU_info->___ebp + FPU_info->___esi; + address += FPU_info->___ebp + FPU_info->___esi; if ( addr_modes.override.segment == PREFIX_DEFAULT ) addr_modes.override.segment = PREFIX_SS_; break; case 3: - offset += FPU_info->___ebp + FPU_info->___edi; + address += FPU_info->___ebp + FPU_info->___edi; if ( addr_modes.override.segment == PREFIX_DEFAULT ) addr_modes.override.segment = PREFIX_SS_; break; case 4: - offset += FPU_info->___esi; + address += FPU_info->___esi; break; case 5: - offset += FPU_info->___edi; + address += FPU_info->___edi; break; case 6: - offset += FPU_info->___ebp; + address += FPU_info->___ebp; if ( addr_modes.override.segment == PREFIX_DEFAULT ) addr_modes.override.segment = PREFIX_SS_; break; case 7: - offset += FPU_info->___ebx; + address += FPU_info->___ebx; break; } add_segment: - offset &= 0xffff; + address &= 0xffff; + + addr->offset = address; - if ( addr_modes.mode16 ) + switch ( addr_modes.default_mode ) { - offset += mode16_segment(addr_modes); + case 0: + break; + case VM86: + address += vm86_segment(addr_modes.override.segment, + (unsigned short *)&(addr->selector)); + break; + case PM16: + case SEG32: + address = pm_address(FPU_modrm, addr_modes.override.segment, + (unsigned short *)&(addr->selector), address); + break; + default: + EXCEPTION(EX_INTERNAL|0x131); } - FPU_data_address = (void *)offset ; + return (void *)address ; } diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/load_store.c linux/drivers/FPU-emu/load_store.c --- v1.1.17/linux/drivers/FPU-emu/load_store.c Mon Feb 14 13:10:46 1994 +++ linux/drivers/FPU-emu/load_store.c Thu Jun 2 10:28:26 1994 @@ -27,12 +27,12 @@ #include "control_w.h" -#define _NONE_ 0 /* FPU_st0_ptr etc not needed */ +#define _NONE_ 0 /* st0_ptr etc not needed */ #define _REG0_ 1 /* Will be storing st(0) */ #define _PUSH_ 3 /* Need to check for space to push onto stack */ #define _null_ 4 /* Function illegal or not implemented */ -#define pop_0() { pop_ptr->tag = TW_Empty; top++; } +#define pop_0() { st0_ptr->tag = TW_Empty; top++; } static unsigned char const type_table[32] = { @@ -46,192 +46,215 @@ _NONE_, _REG0_, _NONE_, _REG0_ }; -void load_store_instr(char type, fpu_addr_modes addr_modes) +unsigned char const data_sizes_16[32] = { + 4, 4, 8, 2, 0, 0, 0, 0, + 4, 4, 8, 2, 4, 4, 8, 2, + 14, 0, 94, 10, 2, 10, 0, 8, + 14, 0, 94, 10, 2, 10, 2, 8 +}; + +unsigned char const data_sizes_32[32] = { + 4, 4, 8, 2, 0, 0, 0, 0, + 4, 4, 8, 2, 4, 4, 8, 2, + 28, 0,108, 10, 2, 10, 0, 8, + 28, 0,108, 10, 2, 10, 2, 8 +}; + +int load_store_instr(unsigned char type, fpu_addr_modes addr_modes, + void *data_address) { - FPU_REG *pop_ptr; /* We need a version of FPU_st0_ptr which won't - change if the emulator is re-entered. */ + FPU_REG loaded_data; + FPU_REG *st0_ptr; + + st0_ptr = NULL; /* Initialized just to stop compiler warnings. */ + + if ( addr_modes.default_mode & PROTECTED ) + { + if ( addr_modes.default_mode == SEG32 ) + { + if ( access_limit < data_sizes_32[type] ) + math_abort(FPU_info,SIGSEGV); + } + else if ( addr_modes.default_mode == PM16 ) + { + if ( access_limit < data_sizes_16[type] ) + math_abort(FPU_info,SIGSEGV); + } +#ifdef PARANOID + else + EXCEPTION(EX_INTERNAL|0x140); +#endif PARANOID + } - pop_ptr = NULL; /* Initialized just to stop compiler warnings. */ - switch ( type_table[(int) (unsigned) type] ) + switch ( type_table[type] ) { case _NONE_: break; case _REG0_: - pop_ptr = &st(0); /* Some of these instructions pop after + st0_ptr = &st(0); /* Some of these instructions pop after storing */ - - FPU_st0_ptr = pop_ptr; /* Set the global variables. */ - FPU_st0_tag = FPU_st0_ptr->tag; break; case _PUSH_: { - pop_ptr = &st(-1); - if ( pop_ptr->tag != TW_Empty ) - { stack_overflow(); return; } + st0_ptr = &st(-1); + if ( st0_ptr->tag != TW_Empty ) + { stack_overflow(); return 0; } top--; } break; case _null_: FPU_illegal(); - return; + return 0; #ifdef PARANOID default: - EXCEPTION(EX_INTERNAL); - return; + EXCEPTION(EX_INTERNAL|0x141); + return 0; #endif PARANOID } -switch ( type ) - { - case 000: /* fld m32real */ - clear_C1(); - reg_load_single(); - if ( (FPU_loaded_data.tag == TW_NaN) && - real_2op_NaN(&FPU_loaded_data, &FPU_loaded_data, &FPU_loaded_data) ) - { - top++; - break; - } - reg_move(&FPU_loaded_data, pop_ptr); - break; - case 001: /* fild m32int */ - clear_C1(); - reg_load_int32(); - reg_move(&FPU_loaded_data, pop_ptr); - break; - case 002: /* fld m64real */ - clear_C1(); - reg_load_double(); - if ( (FPU_loaded_data.tag == TW_NaN) && - real_2op_NaN(&FPU_loaded_data, &FPU_loaded_data, &FPU_loaded_data) ) - { - top++; - break; - } - reg_move(&FPU_loaded_data, pop_ptr); - break; - case 003: /* fild m16int */ - clear_C1(); - reg_load_int16(); - reg_move(&FPU_loaded_data, pop_ptr); - break; - case 010: /* fst m32real */ - clear_C1(); - reg_store_single(); - break; - case 011: /* fist m32int */ - clear_C1(); - reg_store_int32(); - break; - case 012: /* fst m64real */ - clear_C1(); - reg_store_double(); - break; - case 013: /* fist m16int */ - clear_C1(); - reg_store_int16(); - break; - case 014: /* fstp m32real */ - clear_C1(); - if ( reg_store_single() ) - pop_0(); /* pop only if the number was actually stored - (see the 80486 manual p16-28) */ - break; - case 015: /* fistp m32int */ - clear_C1(); - if ( reg_store_int32() ) - pop_0(); /* pop only if the number was actually stored - (see the 80486 manual p16-28) */ - break; - case 016: /* fstp m64real */ - clear_C1(); - if ( reg_store_double() ) - pop_0(); /* pop only if the number was actually stored - (see the 80486 manual p16-28) */ - break; - case 017: /* fistp m16int */ - clear_C1(); - if ( reg_store_int16() ) - pop_0(); /* pop only if the number was actually stored - (see the 80486 manual p16-28) */ - break; - case 020: /* fldenv m14/28byte */ - fldenv(addr_modes); - break; - case 022: /* frstor m94/108byte */ - frstor(addr_modes); - break; - case 023: /* fbld m80dec */ - clear_C1(); - reg_load_bcd(); - reg_move(&FPU_loaded_data, pop_ptr); - break; - case 024: /* fldcw */ - RE_ENTRANT_CHECK_OFF; - FPU_verify_area(VERIFY_READ, FPU_data_address, 2); - control_word = get_fs_word((unsigned short *) FPU_data_address); - RE_ENTRANT_CHECK_ON; - if ( partial_status & ~control_word & CW_Exceptions ) - partial_status |= (SW_Summary | SW_Backward); - else - partial_status &= ~(SW_Summary | SW_Backward); + switch ( type ) + { + case 000: /* fld m32real */ + clear_C1(); + reg_load_single((float *)data_address, &loaded_data); + if ( (loaded_data.tag == TW_NaN) && + real_2op_NaN(&loaded_data, &loaded_data, &loaded_data) ) + { + top++; + break; + } + reg_move(&loaded_data, st0_ptr); + break; + case 001: /* fild m32int */ + clear_C1(); + reg_load_int32((long *)data_address, st0_ptr); + break; + case 002: /* fld m64real */ + clear_C1(); + reg_load_double((double *)data_address, &loaded_data); + if ( (loaded_data.tag == TW_NaN) && + real_2op_NaN(&loaded_data, &loaded_data, &loaded_data) ) + { + top++; + break; + } + reg_move(&loaded_data, st0_ptr); + break; + case 003: /* fild m16int */ + clear_C1(); + reg_load_int16((short *)data_address, st0_ptr); + break; + case 010: /* fst m32real */ + clear_C1(); + reg_store_single((float *)data_address, st0_ptr); + break; + case 011: /* fist m32int */ + clear_C1(); + reg_store_int32((long *)data_address, st0_ptr); + break; + case 012: /* fst m64real */ + clear_C1(); + reg_store_double((double *)data_address, st0_ptr); + break; + case 013: /* fist m16int */ + clear_C1(); + reg_store_int16((short *)data_address, st0_ptr); + break; + case 014: /* fstp m32real */ + clear_C1(); + if ( reg_store_single((float *)data_address, st0_ptr) ) + pop_0(); /* pop only if the number was actually stored + (see the 80486 manual p16-28) */ + break; + case 015: /* fistp m32int */ + clear_C1(); + if ( reg_store_int32((long *)data_address, st0_ptr) ) + pop_0(); /* pop only if the number was actually stored + (see the 80486 manual p16-28) */ + break; + case 016: /* fstp m64real */ + clear_C1(); + if ( reg_store_double((double *)data_address, st0_ptr) ) + pop_0(); /* pop only if the number was actually stored + (see the 80486 manual p16-28) */ + break; + case 017: /* fistp m16int */ + clear_C1(); + if ( reg_store_int16((short *)data_address, st0_ptr) ) + pop_0(); /* pop only if the number was actually stored + (see the 80486 manual p16-28) */ + break; + case 020: /* fldenv m14/28byte */ + fldenv(addr_modes, (char *)data_address); + /* Ensure that the values just loaded are not changed by + fix-up operations. */ + return 1; + case 022: /* frstor m94/108byte */ + frstor(addr_modes, (char *)data_address); + /* Ensure that the values just loaded are not changed by + fix-up operations. */ + return 1; + case 023: /* fbld m80dec */ + clear_C1(); + reg_load_bcd((char *)data_address, st0_ptr); + break; + case 024: /* fldcw */ + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_READ, data_address, 2); + control_word = get_fs_word((unsigned short *) data_address); + RE_ENTRANT_CHECK_ON; + if ( partial_status & ~control_word & CW_Exceptions ) + partial_status |= (SW_Summary | SW_Backward); + else + partial_status &= ~(SW_Summary | SW_Backward); #ifdef PECULIAR_486 - control_word |= 0x40; /* An 80486 appears to always set this bit */ + control_word |= 0x40; /* An 80486 appears to always set this bit */ #endif PECULIAR_486 - NO_NET_DATA_EFFECT; - NO_NET_INSTR_EFFECT; - break; - case 025: /* fld m80real */ - clear_C1(); - reg_load_extended(); - reg_move(&FPU_loaded_data, pop_ptr); - break; - case 027: /* fild m64int */ - clear_C1(); - reg_load_int64(); - reg_move(&FPU_loaded_data, pop_ptr); - break; - case 030: /* fstenv m14/28byte */ - fstenv(addr_modes); - NO_NET_DATA_EFFECT; - break; - case 032: /* fsave */ - fsave(addr_modes); - NO_NET_DATA_EFFECT; - break; - case 033: /* fbstp m80dec */ - clear_C1(); - if ( reg_store_bcd() ) - pop_0(); /* pop only if the number was actually stored - (see the 80486 manual p16-28) */ - break; - case 034: /* fstcw m16int */ - RE_ENTRANT_CHECK_OFF; - FPU_verify_area(VERIFY_WRITE,FPU_data_address,2); - put_fs_word(control_word, (short *) FPU_data_address); - RE_ENTRANT_CHECK_ON; - NO_NET_DATA_EFFECT; - NO_NET_INSTR_EFFECT; - break; - case 035: /* fstp m80real */ - clear_C1(); - if ( reg_store_extended() ) - pop_0(); /* pop only if the number was actually stored - (see the 80486 manual p16-28) */ - break; - case 036: /* fstsw m2byte */ - RE_ENTRANT_CHECK_OFF; - FPU_verify_area(VERIFY_WRITE,FPU_data_address,2); - put_fs_word(status_word(),(short *) FPU_data_address); - RE_ENTRANT_CHECK_ON; - NO_NET_DATA_EFFECT; - NO_NET_INSTR_EFFECT; - break; - case 037: /* fistp m64int */ - clear_C1(); - if ( reg_store_int64() ) - pop_0(); /* pop only if the number was actually stored - (see the 80486 manual p16-28) */ - break; - } + return 1; + case 025: /* fld m80real */ + clear_C1(); + reg_load_extended((long double *)data_address, st0_ptr); + break; + case 027: /* fild m64int */ + clear_C1(); + reg_load_int64((long long *)data_address, st0_ptr); + break; + case 030: /* fstenv m14/28byte */ + fstenv(addr_modes, (char *)data_address); + return 1; + case 032: /* fsave */ + fsave(addr_modes, (char *)data_address); + return 1; + case 033: /* fbstp m80dec */ + clear_C1(); + if ( reg_store_bcd((char *)data_address, st0_ptr) ) + pop_0(); /* pop only if the number was actually stored + (see the 80486 manual p16-28) */ + break; + case 034: /* fstcw m16int */ + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,data_address,2); + put_fs_word(control_word, (short *) data_address); + RE_ENTRANT_CHECK_ON; + return 1; + case 035: /* fstp m80real */ + clear_C1(); + if ( reg_store_extended((long double *)data_address, st0_ptr) ) + pop_0(); /* pop only if the number was actually stored + (see the 80486 manual p16-28) */ + break; + case 036: /* fstsw m2byte */ + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,data_address,2); + put_fs_word(status_word(),(short *) data_address); + RE_ENTRANT_CHECK_ON; + return 1; + case 037: /* fistp m64int */ + clear_C1(); + if ( reg_store_int64((long long *)data_address, st0_ptr) ) + pop_0(); /* pop only if the number was actually stored + (see the 80486 manual p16-28) */ + break; + } + return 0; } diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/poly_atan.c linux/drivers/FPU-emu/poly_atan.c --- v1.1.17/linux/drivers/FPU-emu/poly_atan.c Wed Dec 1 14:44:16 1993 +++ linux/drivers/FPU-emu/poly_atan.c Thu Jun 2 10:28:26 1994 @@ -187,15 +187,7 @@ for the use of this function in poly_atan. Simple truncation is used here instead of round-to-nearest. */ -#ifdef OBSOLETE -char round = (src->sigl & 3) == 3; -#endif OBSOLETE - shrx(&src->sigl, 1); - -#ifdef OBSOLETE -if ( round ) significand(src)++; /* Round to even */ -#endif OBSOLETE src->sigh |= 0x80000000; diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/reg_compare.c linux/drivers/FPU-emu/reg_compare.c --- v1.1.17/linux/drivers/FPU-emu/reg_compare.c Thu Feb 3 12:11:39 1994 +++ linux/drivers/FPU-emu/reg_compare.c Thu Jun 2 10:28:27 1994 @@ -24,10 +24,15 @@ int compare(FPU_REG const *b) { int diff; + char st0_tag; + FPU_REG *st0_ptr; - if ( FPU_st0_ptr->tag | b->tag ) + st0_ptr = &st(0); + st0_tag = st0_ptr->tag; + + if ( st0_tag | b->tag ) { - if ( FPU_st0_ptr->tag == TW_Zero ) + if ( st0_tag == TW_Zero ) { if ( b->tag == TW_Zero ) return COMP_A_eq_B; if ( b->tag == TW_Valid ) @@ -42,23 +47,23 @@ } else if ( b->tag == TW_Zero ) { - if ( FPU_st0_ptr->tag == TW_Valid ) + if ( st0_tag == TW_Valid ) { - return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B + return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B) #ifdef DENORM_OPERAND - | ((FPU_st0_ptr->exp <= EXP_UNDER ) + | ((st0_ptr->exp <= EXP_UNDER ) ? COMP_Denormal : 0 ) #endif DENORM_OPERAND ; } } - if ( FPU_st0_ptr->tag == TW_Infinity ) + if ( st0_tag == TW_Infinity ) { if ( (b->tag == TW_Valid) || (b->tag == TW_Zero) ) { - return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B + return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B) #ifdef DENORM_OPERAND | (((b->tag == TW_Valid) && (b->exp <= EXP_UNDER)) ? @@ -69,19 +74,19 @@ else if ( b->tag == TW_Infinity ) { /* The 80486 book says that infinities can be equal! */ - return (FPU_st0_ptr->sign == b->sign) ? COMP_A_eq_B : - ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B); + return (st0_ptr->sign == b->sign) ? COMP_A_eq_B : + ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B); } /* Fall through to the NaN code */ } else if ( b->tag == TW_Infinity ) { - if ( (FPU_st0_ptr->tag == TW_Valid) || (FPU_st0_ptr->tag == TW_Zero) ) + if ( (st0_tag == TW_Valid) || (st0_tag == TW_Zero) ) { return ((b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B) #ifdef DENORM_OPERAND - | (((FPU_st0_ptr->tag == TW_Valid) - && (FPU_st0_ptr->exp <= EXP_UNDER)) ? + | (((st0_tag == TW_Valid) + && (st0_ptr->exp <= EXP_UNDER)) ? COMP_Denormal : 0) #endif DENORM_OPERAND ; @@ -91,9 +96,9 @@ /* The only possibility now should be that one of the arguments is a NaN */ - if ( (FPU_st0_ptr->tag == TW_NaN) || (b->tag == TW_NaN) ) + if ( (st0_tag == TW_NaN) || (b->tag == TW_NaN) ) { - if ( ((FPU_st0_ptr->tag == TW_NaN) && !(FPU_st0_ptr->sigh & 0x40000000)) + if ( ((st0_tag == TW_NaN) && !(st0_ptr->sigh & 0x40000000)) || ((b->tag == TW_NaN) && !(b->sigh & 0x40000000)) ) /* At least one arg is a signaling NaN */ return COMP_No_Comp | COMP_SNaN | COMP_NaN; @@ -106,51 +111,51 @@ } #ifdef PARANOID - if (!(FPU_st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid); + if (!(st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid); if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid); #endif PARANOID - if (FPU_st0_ptr->sign != b->sign) + if (st0_ptr->sign != b->sign) { - return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B) + return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B) #ifdef DENORM_OPERAND | - ( ((FPU_st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ? + ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ? COMP_Denormal : 0) #endif DENORM_OPERAND ; } - diff = FPU_st0_ptr->exp - b->exp; + diff = st0_ptr->exp - b->exp; if ( diff == 0 ) { - diff = FPU_st0_ptr->sigh - b->sigh; /* Works only if ms bits are + diff = st0_ptr->sigh - b->sigh; /* Works only if ms bits are identical */ if ( diff == 0 ) { - diff = FPU_st0_ptr->sigl > b->sigl; + diff = st0_ptr->sigl > b->sigl; if ( diff == 0 ) - diff = -(FPU_st0_ptr->sigl < b->sigl); + diff = -(st0_ptr->sigl < b->sigl); } } if ( diff > 0 ) { - return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B) + return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B) #ifdef DENORM_OPERAND | - ( ((FPU_st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ? + ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ? COMP_Denormal : 0) #endif DENORM_OPERAND ; } if ( diff < 0 ) { - return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B) + return ((st0_ptr->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B) #ifdef DENORM_OPERAND | - ( ((FPU_st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ? + ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ? COMP_Denormal : 0) #endif DENORM_OPERAND ; @@ -159,7 +164,7 @@ return COMP_A_eq_B #ifdef DENORM_OPERAND | - ( ((FPU_st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ? + ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ? COMP_Denormal : 0) #endif DENORM_OPERAND ; @@ -168,11 +173,11 @@ /* This function requires that st(0) is not empty */ -int compare_st_data(void) +int compare_st_data(FPU_REG const *loaded_data) { int f, c; - c = compare(&FPU_loaded_data); + c = compare(loaded_data); if (c & COMP_NaN) { @@ -214,7 +219,7 @@ { int f, c; - if ( !NOT_EMPTY_0 || !NOT_EMPTY(nr) ) + if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) ) { setcc(SW_C3 | SW_C2 | SW_C0); /* Stack fault */ @@ -264,7 +269,7 @@ { int f, c; - if ( !NOT_EMPTY_0 || !NOT_EMPTY(nr) ) + if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) ) { setcc(SW_C3 | SW_C2 | SW_C0); /* Stack fault */ @@ -340,10 +345,7 @@ return; } if ( !compare_st_st(1) ) - { - pop(); FPU_st0_ptr = &st(0); - pop(); - } + poppop(); } @@ -369,10 +371,7 @@ if (FPU_rm == 1) { if ( !compare_u_st_st(1) ) - { - pop(); FPU_st0_ptr = &st(0); - pop(); - } + poppop(); } else FPU_illegal(); diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/reg_constant.c linux/drivers/FPU-emu/reg_constant.c --- v1.1.17/linux/drivers/FPU-emu/reg_constant.c Thu Feb 3 12:11:40 1994 +++ linux/drivers/FPU-emu/reg_constant.c Thu Jun 2 10:28:27 1994 @@ -66,7 +66,7 @@ return; } push(); - reg_move(c, FPU_st0_ptr); + reg_move(c, st_new_ptr); clear_C1(); } diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/reg_div.S linux/drivers/FPU-emu/reg_div.S --- v1.1.17/linux/drivers/FPU-emu/reg_div.S Thu Feb 3 12:11:40 1994 +++ linux/drivers/FPU-emu/reg_div.S Thu Jun 2 10:28:27 1994 @@ -25,9 +25,9 @@ _reg_div: pushl %ebp movl %esp,%ebp -#ifdef REENTRANT_FPU +#ifndef NON_REENTRANT_FPU subl $28,%esp /* Needed by divide_kernel */ -#endif REENTRANT_FPU +#endif NON_REENTRANT_FPU pushl %esi pushl %edi @@ -214,11 +214,11 @@ xorl %eax,%eax /* Valid result */ LDiv_exit: -#ifdef REENTRANT_FPU +#ifndef NON_REENTRANT_FPU leal -40(%ebp),%esp #else leal -12(%ebp),%esp -#endif REENTRANT_FPU +#endif NON_REENTRANT_FPU popl %ebx popl %edi diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/reg_ld_str.c linux/drivers/FPU-emu/reg_ld_str.c --- v1.1.17/linux/drivers/FPU-emu/reg_ld_str.c Tue May 24 00:34:46 1994 +++ linux/drivers/FPU-emu/reg_ld_str.c Thu Jun 2 10:28:28 1994 @@ -40,42 +40,34 @@ static void write_to_extended(FPU_REG *rp, char *d); -FPU_REG FPU_loaded_data; - /* Get a long double from user memory */ -int reg_load_extended(void) +int reg_load_extended(long double *s, FPU_REG *loaded_data) { - long double *s = (long double *)FPU_data_address; unsigned long sigl, sigh, exp; RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_READ, s, 10); - /* Use temporary variables here because FPU_loaded data is - static and hence re-entrancy problems can arise */ sigl = get_fs_long((unsigned long *) s); sigh = get_fs_long(1 + (unsigned long *) s); exp = get_fs_word(4 + (unsigned short *) s); RE_ENTRANT_CHECK_ON; - FPU_loaded_data.tag = TW_Valid; /* Default */ - FPU_loaded_data.sigl = sigl; - FPU_loaded_data.sigh = sigh; + loaded_data->tag = TW_Valid; /* Default */ + loaded_data->sigl = sigl; + loaded_data->sigh = sigh; if (exp & 0x8000) - FPU_loaded_data.sign = SIGN_NEG; + loaded_data->sign = SIGN_NEG; else - FPU_loaded_data.sign = SIGN_POS; + loaded_data->sign = SIGN_POS; exp &= 0x7fff; - FPU_loaded_data.exp = exp - EXTENDED_Ebias + EXP_BIAS; + loaded_data->exp = exp - EXTENDED_Ebias + EXP_BIAS; - /* Assume that optimisation can keep sigl, sigh, and exp in - registers, otherwise it would be more efficient to work - with FPU_loaded_data (which is static) here. */ if ( exp == 0 ) { if ( !(sigh | sigl) ) { - FPU_loaded_data.tag = TW_Zero; + loaded_data->tag = TW_Zero; return 0; } /* The number is a de-normal or pseudodenormal. */ @@ -85,15 +77,15 @@ /* Convert it for internal use. */ /* This is non-80486 behaviour because the number loses its 'denormal' identity. */ - FPU_loaded_data.exp++; + loaded_data->exp++; return 1; } else { /* Is a denormal. */ /* Convert it for internal use. */ - FPU_loaded_data.exp++; - normalize_nuo(&FPU_loaded_data); + loaded_data->exp++; + normalize_nuo(loaded_data); return 0; } } @@ -102,13 +94,13 @@ if ( !((sigh ^ 0x80000000) | sigl) ) { /* Matches the bit pattern for Infinity. */ - FPU_loaded_data.exp = EXP_Infinity; - FPU_loaded_data.tag = TW_Infinity; + loaded_data->exp = EXP_Infinity; + loaded_data->tag = TW_Infinity; return 0; } - FPU_loaded_data.exp = EXP_NaN; - FPU_loaded_data.tag = TW_NaN; + loaded_data->exp = EXP_NaN; + loaded_data->tag = TW_NaN; if ( !(sigh & 0x80000000) ) { /* NaNs have the ms bit set to 1. */ @@ -116,9 +108,9 @@ /* This is non 80486 behaviour */ /* This should generate an Invalid Operand exception later, so we convert it to a SNaN */ - FPU_loaded_data.sigh = 0x80000000; - FPU_loaded_data.sigl = 0x00000001; - FPU_loaded_data.sign = SIGN_NEG; + loaded_data->sigh = 0x80000000; + loaded_data->sigl = 0x00000001; + loaded_data->sign = SIGN_NEG; return 1; } return 0; @@ -133,11 +125,11 @@ /* This is non-80486 behaviour */ /* This should generate an Invalid Operand exception later, so we convert it to a SNaN */ - FPU_loaded_data.sigh = 0x80000000; - FPU_loaded_data.sigl = 0x00000001; - FPU_loaded_data.sign = SIGN_NEG; - FPU_loaded_data.exp = EXP_NaN; - FPU_loaded_data.tag = TW_NaN; + loaded_data->sigh = 0x80000000; + loaded_data->sigl = 0x00000001; + loaded_data->sign = SIGN_NEG; + loaded_data->exp = EXP_NaN; + loaded_data->tag = TW_NaN; return 1; } return 0; @@ -145,9 +137,8 @@ /* Get a double from user memory */ -int reg_load_double(void) +int reg_load_double(double *dfloat, FPU_REG *loaded_data) { - double *dfloat = (double *)FPU_data_address; int exp; unsigned m64, l64; @@ -158,9 +149,9 @@ RE_ENTRANT_CHECK_ON; if (m64 & 0x80000000) - FPU_loaded_data.sign = SIGN_NEG; + loaded_data->sign = SIGN_NEG; else - FPU_loaded_data.sign = SIGN_POS; + loaded_data->sign = SIGN_POS; exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias; m64 &= 0xfffff; if (exp > DOUBLE_Emax) @@ -169,20 +160,20 @@ if ((m64 == 0) && (l64 == 0)) { /* +- infinity */ - FPU_loaded_data.sigh = 0x80000000; - FPU_loaded_data.sigl = 0x00000000; - FPU_loaded_data.exp = EXP_Infinity; - FPU_loaded_data.tag = TW_Infinity; + loaded_data->sigh = 0x80000000; + loaded_data->sigl = 0x00000000; + loaded_data->exp = EXP_Infinity; + loaded_data->tag = TW_Infinity; return 0; } else { /* Must be a signaling or quiet NaN */ - FPU_loaded_data.exp = EXP_NaN; - FPU_loaded_data.tag = TW_NaN; - FPU_loaded_data.sigh = (m64 << 11) | 0x80000000; - FPU_loaded_data.sigh |= l64 >> 21; - FPU_loaded_data.sigl = l64 << 11; + loaded_data->exp = EXP_NaN; + loaded_data->tag = TW_NaN; + loaded_data->sigh = (m64 << 11) | 0x80000000; + loaded_data->sigh |= l64 >> 21; + loaded_data->sigl = l64 << 11; return 0; /* The calling function must look for NaNs */ } } @@ -192,30 +183,30 @@ if ((m64 == 0) && (l64 == 0)) { /* Zero */ - int c = FPU_loaded_data.sign; - reg_move(&CONST_Z, &FPU_loaded_data); - FPU_loaded_data.sign = c; + int c = loaded_data->sign; + reg_move(&CONST_Z, loaded_data); + loaded_data->sign = c; return 0; } else { /* De-normal */ - FPU_loaded_data.exp = DOUBLE_Emin + EXP_BIAS; - FPU_loaded_data.tag = TW_Valid; - FPU_loaded_data.sigh = m64 << 11; - FPU_loaded_data.sigh |= l64 >> 21; - FPU_loaded_data.sigl = l64 << 11; - normalize_nuo(&FPU_loaded_data); + loaded_data->exp = DOUBLE_Emin + EXP_BIAS; + loaded_data->tag = TW_Valid; + loaded_data->sigh = m64 << 11; + loaded_data->sigh |= l64 >> 21; + loaded_data->sigl = l64 << 11; + normalize_nuo(loaded_data); return denormal_operand(); } } else { - FPU_loaded_data.exp = exp + EXP_BIAS; - FPU_loaded_data.tag = TW_Valid; - FPU_loaded_data.sigh = (m64 << 11) | 0x80000000; - FPU_loaded_data.sigh |= l64 >> 21; - FPU_loaded_data.sigl = l64 << 11; + loaded_data->exp = exp + EXP_BIAS; + loaded_data->tag = TW_Valid; + loaded_data->sigh = (m64 << 11) | 0x80000000; + loaded_data->sigh |= l64 >> 21; + loaded_data->sigl = l64 << 11; return 0; } @@ -223,9 +214,8 @@ /* Get a float from user memory */ -int reg_load_single(void) +int reg_load_single(float *single, FPU_REG *loaded_data) { - float *single = (float *)FPU_data_address; unsigned m32; int exp; @@ -235,15 +225,15 @@ RE_ENTRANT_CHECK_ON; if (m32 & 0x80000000) - FPU_loaded_data.sign = SIGN_NEG; + loaded_data->sign = SIGN_NEG; else - FPU_loaded_data.sign = SIGN_POS; + loaded_data->sign = SIGN_POS; if (!(m32 & 0x7fffffff)) { /* Zero */ - int c = FPU_loaded_data.sign; - reg_move(&CONST_Z, &FPU_loaded_data); - FPU_loaded_data.sign = c; + int c = loaded_data->sign; + reg_move(&CONST_Z, loaded_data); + loaded_data->sign = c; return 0; } exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias; @@ -251,11 +241,11 @@ if ( exp < SINGLE_Emin ) { /* De-normals */ - FPU_loaded_data.exp = SINGLE_Emin + EXP_BIAS; - FPU_loaded_data.tag = TW_Valid; - FPU_loaded_data.sigh = m32; - FPU_loaded_data.sigl = 0; - normalize_nuo(&FPU_loaded_data); + loaded_data->exp = SINGLE_Emin + EXP_BIAS; + loaded_data->tag = TW_Valid; + loaded_data->sigh = m32; + loaded_data->sigl = 0; + normalize_nuo(loaded_data); return denormal_operand(); } else if ( exp > SINGLE_Emax ) @@ -264,37 +254,36 @@ if ( m32 == 0 ) { /* +- infinity */ - FPU_loaded_data.sigh = 0x80000000; - FPU_loaded_data.sigl = 0x00000000; - FPU_loaded_data.exp = EXP_Infinity; - FPU_loaded_data.tag = TW_Infinity; + loaded_data->sigh = 0x80000000; + loaded_data->sigl = 0x00000000; + loaded_data->exp = EXP_Infinity; + loaded_data->tag = TW_Infinity; return 0; } else { /* Must be a signaling or quiet NaN */ - FPU_loaded_data.exp = EXP_NaN; - FPU_loaded_data.tag = TW_NaN; - FPU_loaded_data.sigh = m32 | 0x80000000; - FPU_loaded_data.sigl = 0; + loaded_data->exp = EXP_NaN; + loaded_data->tag = TW_NaN; + loaded_data->sigh = m32 | 0x80000000; + loaded_data->sigl = 0; return 0; /* The calling function must look for NaNs */ } } else { - FPU_loaded_data.exp = exp + EXP_BIAS; - FPU_loaded_data.sigh = m32 | 0x80000000; - FPU_loaded_data.sigl = 0; - FPU_loaded_data.tag = TW_Valid; + loaded_data->exp = exp + EXP_BIAS; + loaded_data->sigh = m32 | 0x80000000; + loaded_data->sigl = 0; + loaded_data->tag = TW_Valid; return 0; } } /* Get a long long from user memory */ -void reg_load_int64(void) +void reg_load_int64(long long *_s, FPU_REG *loaded_data) { - long long *_s = (long long *)FPU_data_address; int e; long long s; @@ -305,28 +294,27 @@ RE_ENTRANT_CHECK_ON; if (s == 0) - { reg_move(&CONST_Z, &FPU_loaded_data); return; } + { reg_move(&CONST_Z, loaded_data); return; } if (s > 0) - FPU_loaded_data.sign = SIGN_POS; + loaded_data->sign = SIGN_POS; else { s = -s; - FPU_loaded_data.sign = SIGN_NEG; + loaded_data->sign = SIGN_NEG; } e = EXP_BIAS + 63; - significand(&FPU_loaded_data) = s; - FPU_loaded_data.exp = e; - FPU_loaded_data.tag = TW_Valid; - normalize_nuo(&FPU_loaded_data); + significand(loaded_data) = s; + loaded_data->exp = e; + loaded_data->tag = TW_Valid; + normalize_nuo(loaded_data); } /* Get a long from user memory */ -void reg_load_int32(void) +void reg_load_int32(long *_s, FPU_REG *loaded_data) { - long *_s = (long *)FPU_data_address; long s; int e; @@ -336,29 +324,28 @@ RE_ENTRANT_CHECK_ON; if (s == 0) - { reg_move(&CONST_Z, &FPU_loaded_data); return; } + { reg_move(&CONST_Z, loaded_data); return; } if (s > 0) - FPU_loaded_data.sign = SIGN_POS; + loaded_data->sign = SIGN_POS; else { s = -s; - FPU_loaded_data.sign = SIGN_NEG; + loaded_data->sign = SIGN_NEG; } e = EXP_BIAS + 31; - FPU_loaded_data.sigh = s; - FPU_loaded_data.sigl = 0; - FPU_loaded_data.exp = e; - FPU_loaded_data.tag = TW_Valid; - normalize_nuo(&FPU_loaded_data); + loaded_data->sigh = s; + loaded_data->sigl = 0; + loaded_data->exp = e; + loaded_data->tag = TW_Valid; + normalize_nuo(loaded_data); } /* Get a short from user memory */ -void reg_load_int16(void) +void reg_load_int16(short *_s, FPU_REG *loaded_data) { - short *_s = (short *)FPU_data_address; int s, e; RE_ENTRANT_CHECK_OFF; @@ -368,30 +355,29 @@ RE_ENTRANT_CHECK_ON; if (s == 0) - { reg_move(&CONST_Z, &FPU_loaded_data); return; } + { reg_move(&CONST_Z, loaded_data); return; } if (s > 0) - FPU_loaded_data.sign = SIGN_POS; + loaded_data->sign = SIGN_POS; else { s = -s; - FPU_loaded_data.sign = SIGN_NEG; + loaded_data->sign = SIGN_NEG; } e = EXP_BIAS + 15; - FPU_loaded_data.sigh = s << 16; + loaded_data->sigh = s << 16; - FPU_loaded_data.sigl = 0; - FPU_loaded_data.exp = e; - FPU_loaded_data.tag = TW_Valid; - normalize_nuo(&FPU_loaded_data); + loaded_data->sigl = 0; + loaded_data->exp = e; + loaded_data->tag = TW_Valid; + normalize_nuo(loaded_data); } /* Get a packed bcd array from user memory */ -void reg_load_bcd(void) +void reg_load_bcd(char *s, FPU_REG *loaded_data) { - char *s = (char *)FPU_data_address; int pos; unsigned char bcd; long long l=0; @@ -409,48 +395,45 @@ l *= 10; l += bcd & 0x0f; } - - /* Finish all access to user memory before putting stuff into - the static FPU_loaded_data */ + RE_ENTRANT_CHECK_OFF; - FPU_loaded_data.sign = + loaded_data->sign = ((unsigned char)get_fs_byte((unsigned char *) s+9)) & 0x80 ? SIGN_NEG : SIGN_POS; RE_ENTRANT_CHECK_ON; if (l == 0) { - char sign = FPU_loaded_data.sign; - reg_move(&CONST_Z, &FPU_loaded_data); - FPU_loaded_data.sign = sign; + char sign = loaded_data->sign; + reg_move(&CONST_Z, loaded_data); + loaded_data->sign = sign; } else { - significand(&FPU_loaded_data) = l; - FPU_loaded_data.exp = EXP_BIAS + 63; - FPU_loaded_data.tag = TW_Valid; - normalize_nuo(&FPU_loaded_data); + significand(loaded_data) = l; + loaded_data->exp = EXP_BIAS + 63; + loaded_data->tag = TW_Valid; + normalize_nuo(loaded_data); } } /*===========================================================================*/ /* Put a long double into user memory */ -int reg_store_extended(void) +int reg_store_extended(long double *d, FPU_REG *st0_ptr) { /* The only exception raised by an attempt to store to an extended format is the Invalid Stack exception, i.e. attempting to store from an empty register. */ - long double *d = (long double *)FPU_data_address; - if ( FPU_st0_tag != TW_Empty ) + if ( st0_ptr->tag != TW_Empty ) { RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_WRITE, d, 10); RE_ENTRANT_CHECK_ON; - write_to_extended(FPU_st0_ptr, (char *) FPU_data_address); + write_to_extended(st0_ptr, (char *) d); return 1; } @@ -475,18 +458,18 @@ /* Put a double into user memory */ -int reg_store_double(void) +int reg_store_double(double *dfloat, FPU_REG *st0_ptr) { - double *dfloat = (double *)FPU_data_address; unsigned long l[2]; unsigned long increment = 0; /* avoid gcc warnings */ + char st0_tag = st0_ptr->tag; - if (FPU_st0_tag == TW_Valid) + if (st0_tag == TW_Valid) { int exp; FPU_REG tmp; - reg_move(FPU_st0_ptr, &tmp); + reg_move(st0_ptr, &tmp); exp = tmp.exp - EXP_BIAS; if ( exp < DOUBLE_Emin ) /* It may be a denormal */ @@ -497,7 +480,7 @@ #ifndef PECULIAR_486 /* An 80486 is supposed to be able to generate a denormal exception here, but... */ - if ( FPU_st0_ptr->exp <= EXP_UNDER ) + if ( st0_ptr->exp <= EXP_UNDER ) { /* Underflow has priority. */ if ( control_word & CW_Underflow ) @@ -515,7 +498,7 @@ that the 80486 rounds to the dest precision, then converts to decide underflow. */ if ( !((tmp.sigh == 0x00100000) && (tmp.sigl == 0) && - (FPU_st0_ptr->sigl & 0x000007ff)) ) + (st0_ptr->sigl & 0x000007ff)) ) #endif PECULIAR_486 { EXCEPTION(EX_Underflow); @@ -612,23 +595,23 @@ } } } - else if (FPU_st0_tag == TW_Zero) + else if (st0_tag == TW_Zero) { /* Number is zero */ l[0] = 0; l[1] = 0; } - else if (FPU_st0_tag == TW_Infinity) + else if (st0_tag == TW_Infinity) { l[0] = 0; l[1] = 0x7ff00000; } - else if (FPU_st0_tag == TW_NaN) + else if (st0_tag == TW_NaN) { /* See if we can get a valid NaN from the FPU_REG */ - l[0] = (FPU_st0_ptr->sigl >> 11) | (FPU_st0_ptr->sigh << 21); - l[1] = ((FPU_st0_ptr->sigh >> 11) & 0xfffff); - if ( !(FPU_st0_ptr->sigh & 0x40000000) ) + l[0] = (st0_ptr->sigl >> 11) | (st0_ptr->sigh << 21); + l[1] = ((st0_ptr->sigh >> 11) & 0xfffff); + if ( !(st0_ptr->sigh & 0x40000000) ) { /* It is a signalling NaN */ EXCEPTION(EX_Invalid); @@ -638,7 +621,7 @@ } l[1] |= 0x7ff00000; } - else if ( FPU_st0_tag == TW_Empty ) + else if ( st0_tag == TW_Empty ) { /* Empty register (stack underflow) */ EXCEPTION(EX_StackUnder); @@ -656,7 +639,7 @@ else return 0; } - if (FPU_st0_ptr->sign) + if ( st0_ptr->sign ) l[1] |= 0x80000000; RE_ENTRANT_CHECK_OFF; @@ -670,18 +653,18 @@ /* Put a float into user memory */ -int reg_store_single(void) +int reg_store_single(float *single, FPU_REG *st0_ptr) { - float *single = (float *)FPU_data_address; long templ; unsigned long increment = 0; /* avoid gcc warnings */ + char st0_tag = st0_ptr->tag; - if (FPU_st0_tag == TW_Valid) + if (st0_tag == TW_Valid) { int exp; FPU_REG tmp; - reg_move(FPU_st0_ptr, &tmp); + reg_move(st0_ptr, &tmp); exp = tmp.exp - EXP_BIAS; if ( exp < SINGLE_Emin ) @@ -692,7 +675,7 @@ #ifndef PECULIAR_486 /* An 80486 is supposed to be able to generate a denormal exception here, but... */ - if ( FPU_st0_ptr->exp <= EXP_UNDER ) + if ( st0_ptr->exp <= EXP_UNDER ) { /* Underflow has priority. */ if ( control_word & CW_Underflow ) @@ -710,7 +693,7 @@ that the 80486 rounds to the dest precision, then converts to decide underflow. */ if ( !((tmp.sigl == 0x00800000) && - ((FPU_st0_ptr->sigh & 0x000000ff) || FPU_st0_ptr->sigl)) ) + ((st0_ptr->sigh & 0x000000ff) || st0_ptr->sigl)) ) #endif PECULIAR_486 { EXCEPTION(EX_Underflow); @@ -800,19 +783,19 @@ templ |= ((exp+SINGLE_Ebias) & 0xff) << 23; } } - else if (FPU_st0_tag == TW_Zero) + else if (st0_tag == TW_Zero) { templ = 0; } - else if (FPU_st0_tag == TW_Infinity) + else if (st0_tag == TW_Infinity) { templ = 0x7f800000; } - else if (FPU_st0_tag == TW_NaN) + else if (st0_tag == TW_NaN) { /* See if we can get a valid NaN from the FPU_REG */ - templ = FPU_st0_ptr->sigh >> 8; - if ( !(FPU_st0_ptr->sigh & 0x40000000) ) + templ = st0_ptr->sigh >> 8; + if ( !(st0_ptr->sigh & 0x40000000) ) { /* It is a signalling NaN */ EXCEPTION(EX_Invalid); @@ -822,7 +805,7 @@ } templ |= 0x7f800000; } - else if ( FPU_st0_tag == TW_Empty ) + else if ( st0_tag == TW_Empty ) { /* Empty register (stack underflow) */ EXCEPTION(EX_StackUnder); @@ -846,7 +829,7 @@ return 0; } #endif - if (FPU_st0_ptr->sign) + if (st0_ptr->sign) templ |= 0x80000000; RE_ENTRANT_CHECK_OFF; @@ -859,27 +842,27 @@ /* Put a long long into user memory */ -int reg_store_int64(void) +int reg_store_int64(long long *d, FPU_REG *st0_ptr) { - long long *d = (long long *)FPU_data_address; FPU_REG t; long long tll; int precision_loss; + char st0_tag = st0_ptr->tag; - if ( FPU_st0_tag == TW_Empty ) + if ( st0_tag == TW_Empty ) { /* Empty register (stack underflow) */ EXCEPTION(EX_StackUnder); goto invalid_operand; } - else if ( (FPU_st0_tag == TW_Infinity) || - (FPU_st0_tag == TW_NaN) ) + else if ( (st0_tag == TW_Infinity) || + (st0_tag == TW_NaN) ) { EXCEPTION(EX_Invalid); goto invalid_operand; } - reg_move(FPU_st0_ptr, &t); + reg_move(st0_ptr, &t); precision_loss = round_to_int(&t); ((long *)&tll)[0] = t.sigl; ((long *)&tll)[1] = t.sigh; @@ -918,26 +901,26 @@ /* Put a long into user memory */ -int reg_store_int32(void) +int reg_store_int32(long *d, FPU_REG *st0_ptr) { - long *d = (long *)FPU_data_address; FPU_REG t; int precision_loss; + char st0_tag = st0_ptr->tag; - if ( FPU_st0_tag == TW_Empty ) + if ( st0_tag == TW_Empty ) { /* Empty register (stack underflow) */ EXCEPTION(EX_StackUnder); goto invalid_operand; } - else if ( (FPU_st0_tag == TW_Infinity) || - (FPU_st0_tag == TW_NaN) ) + else if ( (st0_tag == TW_Infinity) || + (st0_tag == TW_NaN) ) { EXCEPTION(EX_Invalid); goto invalid_operand; } - reg_move(FPU_st0_ptr, &t); + reg_move(st0_ptr, &t); precision_loss = round_to_int(&t); if (t.sigh || ((t.sigl & 0x80000000) && @@ -972,26 +955,26 @@ /* Put a short into user memory */ -int reg_store_int16(void) +int reg_store_int16(short *d, FPU_REG *st0_ptr) { - short *d = (short *)FPU_data_address; FPU_REG t; int precision_loss; + char st0_tag = st0_ptr->tag; - if ( FPU_st0_tag == TW_Empty ) + if ( st0_tag == TW_Empty ) { /* Empty register (stack underflow) */ EXCEPTION(EX_StackUnder); goto invalid_operand; } - else if ( (FPU_st0_tag == TW_Infinity) || - (FPU_st0_tag == TW_NaN) ) + else if ( (st0_tag == TW_Infinity) || + (st0_tag == TW_NaN) ) { EXCEPTION(EX_Invalid); goto invalid_operand; } - reg_move(FPU_st0_ptr, &t); + reg_move(st0_ptr, &t); precision_loss = round_to_int(&t); if (t.sigh || ((t.sigl & 0xffff8000) && @@ -1026,23 +1009,23 @@ /* Put a packed bcd array into user memory */ -int reg_store_bcd(void) +int reg_store_bcd(char *d, FPU_REG *st0_ptr) { - char *d = (char *)FPU_data_address; FPU_REG t; unsigned long long ll; unsigned char b; int i, precision_loss; - unsigned char sign = (FPU_st0_ptr->sign == SIGN_NEG) ? 0x80 : 0; + unsigned char sign = (st0_ptr->sign == SIGN_NEG) ? 0x80 : 0; + char st0_tag = st0_ptr->tag; - if ( FPU_st0_tag == TW_Empty ) + if ( st0_tag == TW_Empty ) { /* Empty register (stack underflow) */ EXCEPTION(EX_StackUnder); goto invalid_operand; } - reg_move(FPU_st0_ptr, &t); + reg_move(st0_ptr, &t); precision_loss = round_to_int(&t); ll = significand(&t); @@ -1163,36 +1146,32 @@ /*===========================================================================*/ -char *fldenv(fpu_addr_modes addr_modes) +char *fldenv(fpu_addr_modes addr_modes, char *s) { - char *s = (char *)FPU_data_address; unsigned short tag_word = 0; unsigned char tag; int i; - if ( addr_modes.mode16 - || (addr_modes.override.operand_size == OP_SIZE_PREFIX) ) + if ( (addr_modes.default_mode == VM86) || + ((addr_modes.default_mode == PM16) + ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) ) { RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_READ, s, 0x0e); control_word = get_fs_word((unsigned short *) s); partial_status = get_fs_word((unsigned short *) (s+2)); tag_word = get_fs_word((unsigned short *) (s+4)); - ip_offset = get_fs_word((unsigned short *) (s+6)); - cs_selector = get_fs_word((unsigned short *) (s+8)); - data_operand_offset = get_fs_word((unsigned short *) (s+0x0a)); - operand_selector = get_fs_word((unsigned short *) (s+0x0c)); + instruction_address.offset = get_fs_word((unsigned short *) (s+6)); + instruction_address.selector = get_fs_word((unsigned short *) (s+8)); + operand_address.offset = get_fs_word((unsigned short *) (s+0x0a)); + operand_address.selector = get_fs_word((unsigned short *) (s+0x0c)); RE_ENTRANT_CHECK_ON; s += 0x0e; - if ( addr_modes.vm86 ) - { - ip_offset += (cs_selector & 0xf000) << 4; - data_operand_offset += (operand_selector & 0xf000) << 4; - } - else if ( addr_modes.p286 ) + if ( addr_modes.default_mode == VM86 ) { - ip_offset += LDT_BASE_ADDR(cs_selector); - data_operand_offset += LDT_BASE_ADDR(operand_selector); + instruction_address.offset + += (instruction_address.selector & 0xf000) << 4; + operand_address.offset += (operand_address.selector & 0xf000) << 4; } } else @@ -1202,10 +1181,11 @@ control_word = get_fs_word((unsigned short *) s); partial_status = get_fs_word((unsigned short *) (s+4)); tag_word = get_fs_word((unsigned short *) (s+8)); - ip_offset = get_fs_long((unsigned long *) (s+0x0c)); - cs_selector = get_fs_long((unsigned long *) (s+0x10)); - data_operand_offset = get_fs_long((unsigned long *) (s+0x14)); - operand_selector = get_fs_long((unsigned long *) (s+0x18)); + instruction_address.offset = get_fs_long((unsigned long *) (s+0x0c)); + instruction_address.selector = get_fs_word((unsigned short *) (s+0x10)); + instruction_address.opcode = get_fs_word((unsigned short *) (s+0x12)); + operand_address.offset = get_fs_long((unsigned long *) (s+0x14)); + operand_address.selector = get_fs_long((unsigned long *) (s+0x18)); RE_ENTRANT_CHECK_ON; s += 0x1c; } @@ -1254,37 +1234,26 @@ remains correct */ } - /* Ensure that the values just loaded are not changed by - fix-up operations. */ - NO_NET_DATA_EFFECT; - NO_NET_INSTR_EFFECT; - return s; } -void frstor(fpu_addr_modes addr_modes) +void frstor(fpu_addr_modes addr_modes, char *data_address) { int i, stnr; unsigned char tag; - char *s = fldenv(addr_modes); + char *s = fldenv(addr_modes, data_address); for ( i = 0; i < 8; i++ ) { /* Load each register. */ - FPU_data_address = (void *)(s+i*10); - reg_load_extended(); stnr = (i+top) & 7; - tag = regs[stnr].tag; /* Derived from the loaded tag word. */ - reg_move(&FPU_loaded_data, ®s[stnr]); + tag = regs[stnr].tag; /* Derived from the fldenv() loaded tag word. */ + reg_load_extended((long double *)(s+i*10), ®s[stnr]); if ( tag == TW_Empty ) /* The loaded data over-rides all other cases. */ regs[stnr].tag = tag; } - /* Reverse the effect which loading the registers had on the - data pointer */ - NO_NET_DATA_EFFECT; - } @@ -1318,12 +1287,11 @@ } -char *fstenv(fpu_addr_modes addr_modes) +char *fstenv(fpu_addr_modes addr_modes, char *d) { - char *d = (char *)FPU_data_address; - - if ( addr_modes.mode16 - || (addr_modes.override.operand_size == OP_SIZE_PREFIX) ) + if ( (addr_modes.default_mode == VM86) || + ((addr_modes.default_mode == PM16) + ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) ) { RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_WRITE,d,14); @@ -1334,19 +1302,19 @@ #endif PECULIAR_486 put_fs_word(status_word(), (unsigned short *) (d+2)); put_fs_word(tag_word(), (unsigned short *) (d+4)); - put_fs_word(ip_offset, (unsigned short *) (d+6)); - put_fs_word(data_operand_offset, (unsigned short *) (d+0x0a)); - if ( addr_modes.vm86 ) + put_fs_word(instruction_address.offset, (unsigned short *) (d+6)); + put_fs_word(operand_address.offset, (unsigned short *) (d+0x0a)); + if ( addr_modes.default_mode == VM86 ) { - put_fs_word((ip_offset & 0xf0000) >> 4, + put_fs_word((instruction_address.offset & 0xf0000) >> 4, (unsigned short *) (d+8)); - put_fs_word((data_operand_offset & 0xf0000) >> 4, + put_fs_word((operand_address.offset & 0xf0000) >> 4, (unsigned short *) (d+0x0c)); } else { - put_fs_word(cs_selector, (unsigned short *) (d+8)); - put_fs_word(operand_selector, (unsigned short *) (d+0x0c)); + put_fs_word(instruction_address.selector, (unsigned short *) (d+8)); + put_fs_word(operand_address.selector, (unsigned short *) (d+0x0c)); } RE_ENTRANT_CHECK_ON; d += 0x0e; @@ -1365,14 +1333,16 @@ put_fs_word(status_word(), (unsigned short *) (d+4)); put_fs_word(tag_word(), (unsigned short *) (d+8)); #endif PECULIAR_486 - put_fs_long(ip_offset, (unsigned long *) (d+0x0c)); - put_fs_long(cs_selector & ~0xf8000000, (unsigned long *) (d+0x10)); - put_fs_long(data_operand_offset, (unsigned long *) (d+0x14)); + put_fs_long(instruction_address.offset, (unsigned long *) (d+0x0c)); + put_fs_word(instruction_address.selector, (unsigned short *) (d+0x10)); + put_fs_word(instruction_address.opcode, (unsigned short *) (d+0x12)); + put_fs_long(operand_address.offset, (unsigned long *) (d+0x14)); #ifdef PECULIAR_486 /* An 80486 sets all the reserved bits to 1. */ - put_fs_long(0xffff0000 | operand_selector, (unsigned long *) (d+0x18)); + put_fs_word(operand_address.selector, (unsigned short *) (d+0x18)); + put_fs_word(0xffff, (unsigned short *) (d+0x1a)); #else - put_fs_long(operand_selector, (unsigned long *) (d+0x18)); + put_fs_long(operand_address.selector, (unsigned long *) (d+0x18)); #endif PECULIAR_486 RE_ENTRANT_CHECK_ON; d += 0x1c; @@ -1385,12 +1355,12 @@ } -void fsave(fpu_addr_modes addr_modes) +void fsave(fpu_addr_modes addr_modes, char *data_address) { char *d; int i; - d = fstenv(addr_modes); + d = fstenv(addr_modes, data_address); RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_WRITE,d,80); RE_ENTRANT_CHECK_ON; diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/reg_round.S linux/drivers/FPU-emu/reg_round.S --- v1.1.17/linux/drivers/FPU-emu/reg_round.S Wed Feb 16 13:07:57 1994 +++ linux/drivers/FPU-emu/reg_round.S Thu Jun 2 10:28:28 1994 @@ -82,7 +82,7 @@ #define UNMASKED_UNDERFLOW $2 -#ifdef REENTRANT_FPU +#ifndef NON_REENTRANT_FPU /* Make the code re-entrant by putting local storage on the stack: */ #define FPU_bits_lost (%esp) @@ -97,7 +97,7 @@ .byte 0 FPU_denormal: .byte 0 -#endif REENTRANT_FPU +#endif NON_REENTRANT_FPU .text @@ -127,9 +127,9 @@ fpu_reg_round_sqrt: /* Entry point from wm_sqrt.S */ -#ifdef REENTRANT_FPU +#ifndef NON_REENTRANT_FPU pushl %ebx /* adjust the stack pointer */ -#endif REENTRANT_FPU +#endif NON_REENTRANT_FPU #ifdef PARANOID /* Cannot use this here yet */ @@ -417,9 +417,9 @@ jge L_overflow fpu_reg_round_exit: -#ifdef REENTRANT_FPU +#ifndef NON_REENTRANT_FPU popl %ebx /* adjust the stack pointer */ -#endif REENTRANT_FPU +#endif NON_REENTRANT_FPU fpu_Arith_exit: popl %ebx diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/reg_u_div.S linux/drivers/FPU-emu/reg_u_div.S --- v1.1.17/linux/drivers/FPU-emu/reg_u_div.S Wed Dec 1 14:44:16 1993 +++ linux/drivers/FPU-emu/reg_u_div.S Thu Jun 2 10:28:28 1994 @@ -29,7 +29,7 @@ /* #define dSIGH(x) 4(x) */ -#ifdef REENTRANT_FPU +#ifndef NON_REENTRANT_FPU /* Local storage on the stack: Result: FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0 @@ -65,7 +65,7 @@ .long 0 FPU_ovfl_flag: .byte 0 -#endif REENTRANT_FPU +#endif NON_REENTRANT_FPU .text @@ -78,9 +78,9 @@ _reg_u_div: pushl %ebp movl %esp,%ebp -#ifdef REENTRANT_FPU +#ifndef NON_REENTRANT_FPU subl $28,%esp -#endif REENTRANT_FPU +#endif NON_REENTRANT_FPU pushl %esi pushl %edi diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/reg_u_mul.S linux/drivers/FPU-emu/reg_u_mul.S --- v1.1.17/linux/drivers/FPU-emu/reg_u_mul.S Wed Dec 1 14:44:16 1993 +++ linux/drivers/FPU-emu/reg_u_mul.S Thu Jun 2 10:28:28 1994 @@ -27,7 +27,7 @@ -#ifdef REENTRANT_FPU +#ifndef NON_REENTRANT_FPU /* Local storage on the stack: */ #define FPU_accum_0 -4(%ebp) /* ms word */ #define FPU_accum_1 -8(%ebp) @@ -40,7 +40,7 @@ .long 0 FPU_accum_1: .long 0 -#endif REENTRANT_FPU +#endif NON_REENTRANT_FPU .text @@ -50,9 +50,9 @@ _reg_u_mul: pushl %ebp movl %esp,%ebp -#ifdef REENTRANT_FPU +#ifndef NON_REENTRANT_FPU subl $8,%esp -#endif REENTRANT_FPU +#endif NON_REENTRANT_FPU pushl %esi pushl %edi diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/version.h linux/drivers/FPU-emu/version.h --- v1.1.17/linux/drivers/FPU-emu/version.h Sat Mar 26 14:04:24 1994 +++ linux/drivers/FPU-emu/version.h Thu Jun 2 10:28:28 1994 @@ -9,5 +9,4 @@ | | +---------------------------------------------------------------------------*/ -#define FPU_VERSION "wm-FPU-emu version Beta 1.11" - +#define FPU_VERSION "wm-FPU-emu version 1.12" diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/wm_sqrt.S linux/drivers/FPU-emu/wm_sqrt.S --- v1.1.17/linux/drivers/FPU-emu/wm_sqrt.S Wed Dec 1 14:44:16 1993 +++ linux/drivers/FPU-emu/wm_sqrt.S Thu Jun 2 10:28:28 1994 @@ -29,7 +29,7 @@ #include "fpu_asm.h" -#ifdef REENTRANT_FPU +#ifndef NON_REENTRANT_FPU /* Local storage on the stack: */ #define FPU_accum_3 -4(%ebp) /* ms word */ #define FPU_accum_2 -8(%ebp) @@ -70,7 +70,7 @@ .long 0 FPU_fsqrt_arg_0: .long 0 /* ls word, at most the ms bit is set */ -#endif REENTRANT_FPU +#endif NON_REENTRANT_FPU .text @@ -80,9 +80,9 @@ _wm_sqrt: pushl %ebp movl %esp,%ebp -#ifdef REENTRANT_FPU +#ifndef NON_REENTRANT_FPU subl $28,%esp -#endif REENTRANT_FPU +#endif NON_REENTRANT_FPU pushl %esi pushl %edi pushl %ebx diff -u --recursive --new-file v1.1.17/linux/drivers/block/README.sbpcd linux/drivers/block/README.sbpcd --- v1.1.17/linux/drivers/block/README.sbpcd Tue Apr 19 10:52:12 1994 +++ linux/drivers/block/README.sbpcd Thu Jun 2 10:33:26 1994 @@ -1,42 +1,59 @@ -This is release 1.4 of the SoundBlaster Pro (Matsushita, Kotobuki, -Panasonic, CreativeLabs, Aztech) CD-ROM driver for Linux. +This README belongs to release 1.6 of the SoundBlaster Pro (Matsushita, +Kotobuki, Panasonic, CreativeLabs) CD-ROM driver for Linux. The driver is able to drive the whole family of IDE-style -Matsushita/Kotobuki/Panasonic drives (the "double speed" versions -like CR-562 and CR-563, too), and it will work with the soundcard -interfaces (SB Pro, SB 16, Galaxy, SoundFX, ...) and/or with -the "no-sound" cards (Panasonic CI-101P, LaserMate, Aztech, ...). +Matsushita/Kotobuki/Panasonic drives (the "double speed" versions like CR-562 +and CR-563, too), and it will work with the soundcard interfaces (SB Pro, +SB 16, Galaxy, SoundFX, ...) and/or with the "no-sound" cards (Panasonic +CI-101P, LaserMate, Aztech, ...). +It should work too now with the "configurable" interface "Sequoia S-1000", +which is found on the Spea Media FX sound card. The interface type has to get configured in /usr/include/linux/sbpcd.h, because the behavior is different. -The driver respects different drive firmware releases - my old drive -is a 2.11, but it should work with "old" drives <2.01 ... >3.00 -and with "new" drives (which count the releases around 0.75 or -1.00). - -Up to 4 drives are supported. CR-52x ("old") and CR-56x ("new") drives -can be mixed, but the CR-521 ones are hard-wired to drive ID 0. -The drives have to use different drive IDs, but the same controller -(it will be a little bit harder to support up to four interface cards - -but I plan to do it the day somebody wishes to connect a fifth drive). -Each drive has to get a unique minor number (0...3), corresponding -to it's drive ID. The drive IDs may be selected freely from 0 to 3 - -they must not be in consecutive order. - -The driver supports reading of data from the CD and playing of -audio tracks. The audio part should run with WorkMan, xcdplayer, -with the "non-X11" products CDplayer and WorkBone - tell me if -it is not compatible with other software. - -MultiSession is supported (but "old" drives lack this capability), -"ManySession" (see below) alternatively. -Photo CDs work, too. At ftp.gwdg.de:/pub/linux/hpcdtoppm/ is a package -to convert photo CD image files. - -The transfer rate will reach 150 kB/sec with "old" drives and -the full 300 kB/sec with double-speed drives. XA (PhotoCD) disks -with "old" drives are as slow as 50 kB/sec. +The driver respects different drive firmware releases - my old drive is a 2.11, +but it should work with "old" drives <2.01 ... >3.00 and with "new" drives +(which count the releases around 0.75 or 1.00). + +Up to 4 drives are supported. CR-52x ("old") and CR-56x ("new") drives can be +mixed, but the CR-521 ones are hard-wired to drive ID 0. + +As Don Carroll, don@ds9.us.dell.com or FIDO 1:382/14, told me, it is possible +to change old drives to any ID, too. He writes in this sense: + "In order to be able to use more than one single speed drive + (they do not have the ID jumpers) you must add a DIP switch + and two resistors. The pads are already on the board next to + the power connector. You will see the silkscreen for the + switch if you remove the top cover. + 1 2 3 4 + ID 0 = x F F x O = "on" + ID 1 = x O F x F = "off" + ID 2 = x F O x x = "don't care" + ID 3 = x O O x + Next to the switch are the positions for R76 (7k) and R78 + (12k). I had to play around with the resistor values - ID 3 + did not work with other values. If the values are not good, + ID 3 behaves like ID 0." + +The drives have to use different drive IDs, but the same controller (it will +be a little bit harder to support up to four interface cards - but I plan to +do it the day somebody wishes to connect a fifth drive). +Each drive has to get a unique minor number (0...3), corresponding to it's +drive ID. The drive IDs may be selected freely from 0 to 3 - they must not be +in consecutive order. + +The driver supports reading of data from the CD and playing of audio tracks. +The audio part should run with WorkMan, xcdplayer, with the "non-X11" products +CDplayer and WorkBone - tell me if it is not compatible with other software. + +MultiSession is supported (even my "old" CR-521 can handle it), "ManySession" +(not recommended, see below) alternatively. +Photo CDs work, too. At ftp.gwdg.de:/pub/linux/hpcdtoppm/ is Hadmut Danisch's +package to convert photo CD image files. +The transfer rate will reach 150 kB/sec with "old" drives and 300 kB/sec with +double-speed drives. XA (PhotoCD) disks with "old" drives give only 50 kB/sec. + This release is part of the standard kernel and consists of - this README file - the driver file linux/drivers/block/sbpcd.c @@ -46,43 +63,47 @@ To install: ----------- -1. Setup your hardware parameters. Though the driver does "auto-probing" - now, this step is recommended for every-day use. - a. Go into /usr/src/linux/include/linux/sbpcd.h and configure - it for your hardware (near the beginning): +1. Setup your hardware parameters. Though the driver does "auto-probing" at a + lot of (not all possible!) addresses, this step is recommended for + every-day use. + a. Go into /usr/src/linux/include/linux/sbpcd.h and configure it for your + hardware (near the beginning): a1. Set it up for the appropriate type of interface board. - Most "compatible" sound boards (for example "Highscreen", - "SoundFX" and "Galaxy") need the "SBPRO 0" setup. The - "no-sound" board from OmniCd needs the "SBPRO 1" setup. + "Original" CreativeLabs sound cards need "SBPRO 1". + Most "compatible" sound cards (for example "Highscreen", "SoundFX" + and "Galaxy") need "SBPRO 0". + The "no-sound" board from OmniCd needs the "SBPRO 1" setup. + The Spea Media FX sound card needs "SBPRO 2". sbpcd.c holds some examples in it's auto-probe list. - a2. Tell the address of your CDROM_PORT. + If you configure "SBPRO" wrong, the playing of audio CDs will work, + but you will not be able to mount a data CD. + a2. Tell the address of your CDROM_PORT (not of the sound port). b. Additionally for 2.a1 and 2.a2, the setup may be done during boot time (via the "kernel command line" or "LILO option"): sbpcd=0x230,SoundBlaster or sbpcd=0x320,LaserMate + or + sbpcd=0x330,SPEA (these strings are case sensitive!). - -2. Do a "make config" and select "yes" for Matsushita CD-ROM - support and for ISO9660 FileSystem support. + This is especially useful if you install a fresh distribution. +2. Do a "make config" and select "yes" for Matsushita CD-ROM support and for + ISO9660 FileSystem support. SCSI and/or SCSI CD-ROM support is not needed. -3. Then do a "make dep", then make the kernel image ("make zlilo" - or else). +3. Then do a "make dep", then make the kernel image ("make zlilo" or else). -4. Make the device file(s). The driver uses definitely and exclusive - the MAJOR 25, so do - +4. Make the device file(s). The driver uses definitely and exclusive the + MAJOR 25, so do mknod /dev/sbpcd b 25 0 (if you have only drive #0) -and/or + and/or mknod /dev/sbpcd0 b 25 0 mknod /dev/sbpcd1 b 25 1 mknod /dev/sbpcd2 b 25 2 mknod /dev/sbpcd3 b 25 3 - to make the node(s). - Take care that you create a node with the same MINOR as your drive - id is. So, if the DOS driver tells you have drive id #3, you have to + Take care that you create a node with the same MINOR as your drive ID is. + So, if the DOS driver tells you have drive id #3, you have to mknod /dev/ b 25 3 If you further make a link like @@ -91,123 +112,120 @@ 5. Reboot with the new kernel. -You should now be able to do "mount -t iso9660 /dev/sbpcd /mnt" -and see the contents of your CD in the /mnt directory, and/or -hear music with "workman -c /dev/sbpcd &". +You should now be able to do "mount -t iso9660 -o block=2048 /dev/sbpcd /mnt" +and see the contents of your CD in the /mnt directory, and/or hear music with +"workman -c /dev/sbpcd &". Things of interest: ------------------- -The driver is configured to try the SoundBlaster Pro type of -interface at I/O port 0x0230 first. If this is not appropriate, -sbpcd.h should get changed (you will find the right place - -just at the beginning). - -No DMA and no IRQ is used, so the IRQ adjusting is not necessary, -and the IRQ line stays free for the SB Pro sound drivers. - -To reduce or increase the amount of kernel messages, edit -sbpcd.c and change the initialization of the variable -"sbpcd_debug". This is the way to get rid of the initial -warning message block, too. - -With "#define MANY_SESSION 1" (sbpcd.c), the driver can use -"many-session" CDs. This will work only with "new" drives like -CR-562 or CR-563. That is NOT multisession - it is a CD -with multiple independent sessions, each containing block -addresses as if it were the only session. With this feature -enabled, the driver will read the LAST session. Without it, -the FIRST session gets read. -If you would like the support of reading "in-between" sessions, -drop me a mail and some food for the soul. :-) -Those "many-session" CDs can get made by CDROM writers like -Philips CDD 521. -If you enable this feature, it is impossible to read true -multisession CDs. +The driver is configured to try the SoundBlaster Pro type of interface at +I/O port 0x0230 first. If this is not appropriate, sbpcd.h should get changed +(you will find the right place - just at the beginning). + +No DMA and no IRQ is used, so the IRQ line stays free for the SB Pro sound +drivers. + +To reduce or increase the amount of kernel messages, edit sbpcd.c and change +the initialization of the variable "sbpcd_debug". This is the way to get rid +of the initial warning message block, too. + +With "#define MANY_SESSION 1" (sbpcd.c), the driver can use "many-session" CDs. +This will work only with "new" drives like CR-562 or CR-563. That is NOT +multisession - it is a CD with multiple independent sessions, each containing +block addresses as if it were the only session. With this feature enabled, the +driver will read the LAST session. Without it, the FIRST session gets read. +If you would like the support of reading "in-between" sessions, drop me a mail +and some food for the soul. :-) +Those "many-session" CDs can get made by CDROM writers like Philips CDD 521. +If you enable this feature, it is impossible to read true multisession CDs. +The driver uses the "variable BLOCK_SIZE" feature. To use it, you have to +specify "block=2048" as a mount option. + Auto-probing at boot time: -------------------------- -The driver does auto-probing at all well-known interface card -addresses now. The idea to do that came from Adam J. Richter -(YGGDRASIL). - -This auto-probing looks first at the configured address resp. -the address submitted by the kernel command line. With this, -it is possible to use this driver within installation boot -floppies, and for any non-standard address, too. - -Auto-probing will make an assumption about the interface type -("SBPRO" or not), based upon the address. That assumption may -be wrong (initialization will be o.k., but you will get I/O -errors during mount). In that case, use the "kernel command -line" feature and specify address & type at boot time to find -out the right setup. - -SBPCD's auto-probing happens before the initialization of the -net drivers. That makes a hang possible if an ethernet card -gets touched. - -For every-day use, address and type should get configured -within sbpcd.h. That will stop the auto-probing due to success -with the first try. +The driver does auto-probing at many well-known interface card addresses. The +idea to do that came from Adam J. Richter (YGGDRASIL). Some well-known +addresses are excluded from auto-probing because they can cause a hang if an +ethernet card gets touched. + +This auto-probing looks first at the configured address resp. the address +submitted by the kernel command line. With this, it is possible to use this +driver within installation boot floppies, and for any non-standard address, +too. + +Auto-probing will make an assumption about the interface type ("SBPRO" or not), +based upon the address. That assumption may be wrong (initialization will be +o.k., but you will get I/O errors during mount). In that case, use the "kernel +command line" feature and specify address & type at boot time to find out the +right setup. + +SBPCD's auto-probing happens before the initialization of the net drivers. That +makes a hang possible if an ethernet card gets touched. + +For every-day use, address and type should get configured within sbpcd.h. That +will stop the auto-probing due to success with the first try. Setting up address and interface type: -------------------------------------- -If your I/O port address is not 0x0230 or if you use a "no-sound" -interface other than OmniCD, you have to look for the #defines -near the beginning of sbpcd.h and configure them: set SBPRO to -0 or 1, and change CDROM_PORT to the address of your CDROM I/O port. - -Most of the "SoundBlaster compatible" cards behave like the -no-sound interfaces! - -With "original" SB Pro cards, an initial setting of CD_volume -through the sound cards MIXER register gets done. That happens -at the end of "sbpcd_init". If you are using a "compatible" -sound card of type "LaserMate", you can change that code to get -it done with your card, too... +If your I/O port address is not 0x0230 or if you use a "no-sound" interface +other than OmniCD, you have to look for the #defines near the beginning of +sbpcd.h and configure them: set SBPRO to 0 or 1 or 2, and change CDROM_PORT to +the address of your CDROM I/O port. + +Most of the "SoundBlaster compatible" cards behave like the no-sound +interfaces! + +With "original" SB Pro cards, an initial setting of CD_volume through the +sound cards MIXER register gets done. That happens at the end of "sbpcd_init". +If you are using a "compatible" sound card of type "LaserMate", you can change +that code to get it done with your card, too... Using audio CDs: ---------------- -Workman, WorkBone, xcdplayer and cdplayer should work good now, -even with the double-speed drives. +Workman, WorkBone, xcdplayer and cdplayer should work good now, even with the +double-speed drives. -The program CDplayer likes to talk to "/dev/mcd" only, xcdplayer -wants "/dev/rsr0", workman loves "/dev/sr0" - so, do the appropriate -links for using them without the need of supplying parameters. +The program CDplayer likes to talk to "/dev/mcd" only, xcdplayer wants +"/dev/rsr0", workman loves "/dev/sr0" - so, do the appropriate links for using +them without the need of supplying parameters. Known problems: --------------- -Currently, the detection of disk change or removal does not -work as good as it should. +Currently, the detection of disk change or removal does not work as good as it +should. + +The "door (un)lock" commands get done at every "(u)mount" (only the "new" +drives support it), but after an unlock, locking again does not work properly. + +All attempts to read the UPC/EAN code result in a stream of zeroes. All my +drives are telling there is no UPC/EAN code on disk or there is, but it is an +all-zero number. -The "door (un)lock" commands get done at every "(u)mount" (only the -"new" drives support it), but after an unlock, locking again does not -work. - -All attempts to read the UPC/EAN code result in a stream of zeroes. -All my drives are telling there is no UPC/EAN code on disk or there -is, but it is an all-zero number. +My attempts to read audio tracks like data files are of no success. Contact me, +if you have an idea, please. -Bug reports, comments, wishes, donations (technical information -is a donation, too :-) etc. to +Bug reports, comments, wishes, donations (technical information is a donation, +too :-) etc. to emoenke@gwdg.de or to eberhard_moenkeberg@rollo.central.de or to my FIDO address: Eberhard Moenkeberg, 2:2437/210.27 -SnailMail address, preferable for CD editors if they want to submit -a free "cooperation" copy: +SnailMail address, preferable for CD editors if they want to submit a free +"cooperation" copy: Eberhard Moenkeberg Reinholdstr. 14 D-37083 Goettingen Germany +--- diff -u --recursive --new-file v1.1.17/linux/drivers/block/blk.h linux/drivers/block/blk.h --- v1.1.17/linux/drivers/block/blk.h Wed Apr 6 10:40:57 1994 +++ linux/drivers/block/blk.h Thu Jun 2 10:33:26 1994 @@ -82,6 +82,9 @@ extern unsigned long hd_init(unsigned long mem_start, unsigned long mem_end); extern unsigned long cdu31a_init(unsigned long mem_start, unsigned long mem_end); extern unsigned long mcd_init(unsigned long mem_start, unsigned long mem_end); +#ifdef CONFIG_SBPCD +extern unsigned long sbpcd_init(unsigned long, unsigned long); +#endif CONFIG_SBPCD extern int is_read_only(int dev); extern void set_device_ro(int dev,int flag); diff -u --recursive --new-file v1.1.17/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v1.1.17/linux/drivers/block/ll_rw_blk.c Tue Apr 19 10:53:18 1994 +++ linux/drivers/block/ll_rw_blk.c Thu Jun 2 10:33:26 1994 @@ -19,10 +19,6 @@ #include "blk.h" -#ifdef CONFIG_SBPCD -extern u_long sbpcd_init(u_long, u_long); -#endif CONFIG_SBPCD - /* * The request-struct contains all necessary data * to load a nr of sectors into memory diff -u --recursive --new-file v1.1.17/linux/drivers/block/sbpcd.c linux/drivers/block/sbpcd.c --- v1.1.17/linux/drivers/block/sbpcd.c Tue May 31 12:48:15 1994 +++ linux/drivers/block/sbpcd.c Thu Jun 2 10:33:27 1994 @@ -5,7 +5,7 @@ * and for "no-sound" interfaces like Lasermate and the * Panasonic CI-101P. * - * NOTE: This is release 1.5. + * NOTE: This is release 1.6. * It works with my SbPro & drive CR-521 V2.11 from 2/92 * and with the new CR-562-B V0.75 on a "naked" Panasonic * CI-101P interface. And vice versa. @@ -76,6 +76,22 @@ * Adapt to kernel 1.1.8 change (have to explicitely include * now). * + * 1.6 Trying to read audio frames as data. Impossible with the current + * drive firmware levels, as it seems. Awaiting any hint. ;-) + * Changed "door unlock": repeat it until success. + * Changed CDROMSTOP routine (stop somewhat "softer" so that Workman + * won't get confused). + * Added a third interface type: Sequoia S-1000, as used with the SPEA + * Media FX sound card. This interface (useable for Sony and Mitsumi + * drives, too) needs a special configuration setup and behaves like a + * LaserMate type after that. Still experimental - I do not have such + * an interface. + * Use the "variable BLOCK_SIZE" feature (2048). But it does only work + * if you give the mount option "block=2048". + * The media_check routine is currently disabled; now that it gets + * called as it should I fear it must get synchronized for not to + * disturb the normal driver's activity. + * * special thanks to Kai Makisara (kai.makisara@vtt.fi) for his fine * elaborated speed-up experiments (and the fabulous results!), for * the "push" towards load-free wait loops, and for the extensive mail @@ -111,6 +127,7 @@ #include #include +/* #undef DS */ #include #include #include @@ -118,13 +135,7 @@ #include #include #include - -#if SBPCD_USE_IRQ -#include -#endif SBPCD_USE_IRQ - #include - #include #include #include @@ -133,7 +144,7 @@ #define MAJOR_NR MATSUSHITA_CDROM_MAJOR #include "blk.h" -#define VERSION "1.5 Eberhard Moenkeberg " +#define VERSION "1.6 Eberhard Moenkeberg " #define SBPCD_DEBUG @@ -159,6 +170,7 @@ #define XA_TEST2 #define TEST_UPC 0 +#define READ_AUDIO 0 /* does not work today (the drives won't read audio) */ /*==========================================================================*/ /*==========================================================================*/ @@ -167,8 +179,14 @@ #undef LONG_TIMING #define LONG_TIMING 1 #endif - /*==========================================================================*/ +#if SBPCD_DIS_IRQ +#define SBPCD_CLI cli() +#define SBPCD_STI sti() +#else +#define SBPCD_CLI +#define SBPCD_STI +#endif SBPCD_DIS_IRQ /*==========================================================================*/ /* * auto-probing address list @@ -201,6 +219,10 @@ 0x650, 0, /* "sound card #9" */ 0x670, 0, /* "sound card #9" */ 0x690, 0, /* "sound card #9" */ + 0x330, 2, /* SPEA Media FX (default) */ + 0x320, 2, /* SPEA Media FX */ + 0x340, 2, /* SPEA Media FX */ + 0x350, 2, /* SPEA Media FX */ #if 0 /* some "hazardous" locations (ethernet cards) */ 0x330, 0, /* Lasermate, CI-101P */ @@ -227,7 +249,7 @@ * pattern for printk selection: * * (1<>1; + if (sbpro_type==1) i=(i&0x01)<<1|(i&0x02)>>1; OUT(CDo_enable,i); DPRINTF((DBG_DID,"SBPCD: switch_drive: drive %d activated.\n",DriveStruct[d].drv_minor)); return (0); @@ -1951,6 +1977,10 @@ { int i; +#if READ_AUDIO + DriveStruct[d].mode=READ_M1; +#endif READ_AUDIO + i=SetSpeed(); if (i<0) { @@ -2139,6 +2169,51 @@ } /*==========================================================================*/ /*==========================================================================*/ +/*==========================================================================*/ +/* + * Called from the timer to check the results of the get-status cmd. + */ +static int sbp_status(void) +{ + int st; + + st=ResponseStatus(); + if (st<0) + { + DPRINTF((DBG_INF,"SBPCD: sbp_status: timeout.\n")); + return (0); + } + + if (!st_spinning) DPRINTF((DBG_SPI,"SBPCD: motor got off - ignoring.\n")); + + if (st_check) + { + DPRINTF((DBG_INF,"SBPCD: st_check detected - retrying.\n")); + return (0); + } + if (!st_door_closed) + { + DPRINTF((DBG_INF,"SBPCD: door is open - retrying.\n")); + return (0); + } + if (!st_caddy_in) + { + DPRINTF((DBG_INF,"SBPCD: disk removed - retrying.\n")); + return (0); + } + if (!st_diskok) + { + DPRINTF((DBG_INF,"SBPCD: !st_diskok detected - retrying.\n")); + return (0); + } + if (st_busy) + { + DPRINTF((DBG_INF,"SBPCD: st_busy detected - retrying.\n")); + return (0); + } + return (1); +} +/*==========================================================================*/ /*==========================================================================*/ /*==========================================================================*/ @@ -2310,14 +2385,8 @@ case CDROMSTOP: /* Spin down the drive */ DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMSTOP entered.\n")); - i=DriveReset(); -#if WORKMAN - DriveStruct[d].CD_changed=0xFF; - DriveStruct[d].diskstate_flags=0; -#endif WORKMAN - DPRINTF((DBG_IOC,"SBPCD: ioctl: DriveReset returns %d\n",i)); + i=xx_Pause_Resume(1); DriveStruct[d].audio_state=0; - i=DiskInfo(); return (0); case CDROMSTART: /* Spin up the drive */ @@ -2396,14 +2465,238 @@ SC.cdsc_absaddr,SC.cdsc_reladdr)); return (0); + case CDROMREADMODE1: + DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMREADMODE1 requested.\n")); + xx_ModeSelect(CD_FRAMESIZE); + xx_ModeSense(); + DriveStruct[d].mode=READ_M1; + return (0); + case CDROMREADMODE2: DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMREADMODE2 requested.\n")); - return (-EINVAL); + xx_ModeSelect(CD_FRAMESIZE_XA); + xx_ModeSense(); + DriveStruct[d].mode=READ_M2; + return (0); - case CDROMREADMODE1: - DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMREADMODE1 requested.\n")); - return (-EINVAL); - +#if READ_AUDIO + case CDROMREADAUDIO: + { /* start of CDROMREADAUDIO */ + + int i=0, j=0, frame, block; + u_int try=0; + u_long timeout; + u_char *p; + u_int data_tries = 0; + u_int data_waits = 0; + u_int data_retrying = 0; + int status_tries; + int error_flag; + struct cdrom_aud aud_arg; + + error_flag=0; + +#if 0 +#define AUD_FRM_SIZ CD_FRAMESIZE_RAW +#else +#define AUD_FRM_SIZ CD_FRAMESIZE_XA +#endif + + DPRINTF((DBG_IOC,"SBPCD: read_audio: ioctl: CDROMREADAUDIO requested.\n")); + + i=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_aud)); + if (i) return (i); + memcpy_fromfs(&aud_arg, (void *) arg, sizeof(struct cdrom_aud)); + i=verify_area(VERIFY_WRITE, aud_arg.buf, AUD_FRM_SIZ); + if (i) return (i); + DPRINTF((DBG_AUD,"SBPCD: read_audio: lba: %d, buffer: %08X\n", aud_arg.lba, aud_arg.buf)); + + DPRINTF((DBG_AUD,"SBPCD: read_audio: before xx_ReadStatus.\n")); + for (data_tries=5; data_tries>0; data_tries--) + { + DPRINTF((DBG_AUD,"SBPCD: data_tries=%d ...\n", data_tries)); + DriveStruct[d].mode=READ_AU; + xx_ModeSelect(AUD_FRM_SIZ); + xx_ModeSense(); + + + for (status_tries=3; status_tries > 0; status_tries--) + { + flags_cmd_out |= f_respo3; + xx_ReadStatus(); + if (sbp_status() != 0) break; + sbp_sleep(1); /* wait a bit, try again */ + } + if (status_tries == 0) + { + DPRINTF((DBG_AUD,"SBPCD: read_audio: sbp_status: failed after 3 tries.\n")); + continue; + } + DPRINTF((DBG_AUD,"SBPCD: read_audio: sbp_status: ok.\n")); + + + block=aud_arg.lba; + flags_cmd_out = f_putcmd | + f_respo2 | + f_ResponseStatus | + f_obey_p_check; + + + + + if (!new_drive) + { + flags_cmd_out |= f_lopsta | f_getsta | f_bit1; + cmd_type=READ_M2; + drvcmd[0]=0x03; /* "read XA frames" command for old drives */ + drvcmd[1]=(block>>16)&0x000000ff; + drvcmd[2]=(block>>8)&0x000000ff; + drvcmd[3]=block&0x000000ff; + drvcmd[4]=0; + drvcmd[5]=1; /* # of frames */ + drvcmd[6]=0; + } + else /* if new_drive */ + { + drvcmd[0]=0x10; /* "read frames" command for new drives */ + lba2msf(block,&drvcmd[1]); /* msf-bin format required */ + drvcmd[4]=0; + drvcmd[5]=0; + drvcmd[6]=1; /* # of frames */ + } + + + + DPRINTF((DBG_AUD,"SBPCD: read_audio: before giving \"read\" command.\n")); + for (i=0;i<7;i++) OUT(CDo_command,drvcmd[i]); + + sbp_sleep(0); + + DPRINTF((DBG_AUD,"SBPCD: read_audio: after giving \"read\" command.\n")); + for (frame=1;frame<2 && !error_flag; frame++) + { + try=maxtim_data; + for (timeout=jiffies+900; ; ) + { + for ( ; try!=0;try--) + { + j=inb(CDi_status); + if (!(j&s_not_data_ready)) break; + if (!(j&s_not_result_ready)) break; + if (!new_drive) if (j&s_attention) break; + } + if (try != 0 || timeout <= jiffies) break; + if (data_retrying == 0) data_waits++; + data_retrying = 1; + sbp_sleep(1); + try = 1; + } + if (try==0) + { + DPRINTF((DBG_INF,"SBPCD: read_audio: sbp_data: CDi_status timeout.\n")); + error_flag++; + break; + } + DPRINTF((DBG_INF,"SBPCD: read_audio: sbp_data: CDi_status ok.\n")); + + if (j&s_not_data_ready) + { + printk("SBPCD: read_audio: sbp_data: DATA_READY timeout.\n"); + error_flag++; + break; + } + + DPRINTF((DBG_AUD,"SBPCD: read_audio: before reading data.\n")); + CLEAR_TIMER; + error_flag=0; + p = DriveStruct[d].aud_buf; + if (sbpro_type==1) OUT(CDo_sel_d_i,0x01); + READ_DATA(CDi_data, p, AUD_FRM_SIZ); + if (sbpro_type==1) OUT(CDo_sel_d_i,0x00); + data_retrying = 0; + } + DPRINTF((DBG_AUD,"SBPCD: read_audio: after reading data.\n")); + if (error_flag) /* must have been spurious D_RDY or (ATTN&&!D_RDY) */ + { + DPRINTF((DBG_AUD,"SBPCD: read_audio: read aborted by drive\n")); +#if 0000 + i=DriveReset(); /* ugly fix to prevent a hang */ +#endif 0000 + continue; + } + + if (!new_drive) + { + i=maxtim_data; + for (timeout=jiffies+900; timeout > jiffies; timeout--) + { + for ( ;i!=0;i--) + { + j=inb(CDi_status); + if (!(j&s_not_data_ready)) break; + if (!(j&s_not_result_ready)) break; + if (j&s_attention) break; + } + if (i != 0 || timeout <= jiffies) break; + sbp_sleep(0); + i = 1; + } + if (i==0) { DPRINTF((DBG_AUD,"SBPCD: read_audio: STATUS TIMEOUT AFTER READ")); } + if (!(j&s_attention)) + { + DPRINTF((DBG_AUD,"SBPCD: read_audio: sbp_data: timeout waiting DRV_ATTN - retrying\n")); + i=DriveReset(); /* ugly fix to prevent a hang */ + continue; + } + } + + do + { + if (!new_drive) xx_ReadStatus(); + i=ResponseStatus(); /* builds status_byte, returns orig. status (old) or faked p_success_old (new) */ + if (i<0) { DPRINTF((DBG_AUD, + "SBPCD: read_audio: xx_ReadStatus error after read: %02X\n", + DriveStruct[d].status_byte)); + continue; /* FIXME */ + } + } + while ((!new_drive)&&(!st_check)&&(!(i&p_success_old))); + if (st_check) + { + i=xx_ReadError(); + DPRINTF((DBG_AUD,"SBPCD: read_audio: xx_ReadError was necessary after read: %02X\n",i)); + continue; + } + memcpy_tofs((u_char *) aud_arg.buf, + (u_char *) DriveStruct[d].aud_buf, AUD_FRM_SIZ); + DPRINTF((DBG_AUD,"SBPCD: read_audio: memcpy_tofs done.\n")); + break; + } + xx_ModeSelect(CD_FRAMESIZE); + xx_ModeSense(); + DriveStruct[d].mode=READ_M1; + + + if (data_tries == 0) + { + DPRINTF((DBG_AUD,"SBPCD: read_audio: failed after 5 tries.\n")); + return (-8); + } + DPRINTF((DBG_AUD,"SBPCD: read_audio: successful return.\n")); + return (0); + } /* end of CDROMREADAUDIO */ +#endif READ_AUDIO + + + + + case BLKRASET: + if(!suser()) return -EACCES; + if(!inode->i_rdev) return -EINVAL; + if(arg > 0xff) return -EINVAL; + read_ahead[MAJOR(inode->i_rdev)] = arg; + return (0); + default: DPRINTF((DBG_IOC,"SBPCD: ioctl: unknown function request %04X\n", cmd)); return (-EINVAL); @@ -2431,63 +2724,6 @@ } /*==========================================================================*/ /* - * We seem to get never an interrupt. - */ -#if SBPCD_USE_IRQ -static void sbpcd_interrupt(int unused) -{ - int st; - - st = inb(CDi_status) & 0xFF; - DPRINTF((DBG_IRQ,"SBPCD: INTERRUPT received - CDi_status=%02X\n", st)); -} -#endif SBPCD_USE_IRQ -/*==========================================================================*/ -/* - * Called from the timer to check the results of the get-status cmd. - */ -static int sbp_status(void) -{ - int st; - - st=ResponseStatus(); - if (st<0) - { - DPRINTF((DBG_INF,"SBPCD: sbp_status: timeout.\n")); - return (0); - } - - if (!st_spinning) DPRINTF((DBG_SPI,"SBPCD: motor got off - ignoring.\n")); - - if (st_check) - { - DPRINTF((DBG_INF,"SBPCD: st_check detected - retrying.\n")); - return (0); - } - if (!st_door_closed) - { - DPRINTF((DBG_INF,"SBPCD: door is open - retrying.\n")); - return (0); - } - if (!st_caddy_in) - { - DPRINTF((DBG_INF,"SBPCD: disk removed - retrying.\n")); - return (0); - } - if (!st_diskok) - { - DPRINTF((DBG_INF,"SBPCD: !st_diskok detected - retrying.\n")); - return (0); - } - if (st_busy) - { - DPRINTF((DBG_INF,"SBPCD: st_busy detected - retrying.\n")); - return (0); - } - return (1); -} -/*==========================================================================*/ -/* * I/O request routine, called from Linux kernel. */ static void do_sbpcd_request(void) @@ -2513,9 +2749,8 @@ switch_drive(dev); INIT_REQUEST; - block = CURRENT->sector; - nsect = CURRENT->nr_sectors; - + block = CURRENT->sector; /* always numbered as 512-byte-pieces */ + nsect = CURRENT->nr_sectors; /* always counted as 512-byte-pieces */ if (CURRENT->cmd != READ) { printk("SBPCD: bad cmd %d\n", CURRENT->cmd); @@ -2523,11 +2758,11 @@ goto request_loop; } + DPRINTF((DBG_BSZ,"SBPCD: read sector %d (%d sectors)\n", block, nsect)); DPRINTF((DBG_MUL,"SBPCD: read LBA %d\n", block/4)); - sbp_transfer(); + sbp_transfer(); /* if we satisfied the request from the buffer, we're done. */ - if (CURRENT->nr_sectors == 0) { end_request(1); @@ -2535,7 +2770,8 @@ } i=prepare(0,0); /* at moment not really a hassle check, but ... */ - if (i!=0) DPRINTF((DBG_INF,"SBPCD: \"prepare\" tells error %d -- ignored\n", i)); + if (i!=0) + DPRINTF((DBG_INF,"SBPCD: \"prepare\" tells error %d -- ignored\n", i)); if (!st_spinning) xx_SpinUp(); @@ -2674,13 +2910,9 @@ drvcmd[5]=0; drvcmd[6]=DriveStruct[d].sbp_read_frames; } -#if SBPCD_DIS_IRQ - cli(); -#endif SBPCD_DIS_IRQ + SBPCD_CLI; for (i=0;i<7;i++) OUT(CDo_command,drvcmd[i]); -#if SBPCD_DIS_IRQ - sti(); -#endif SBPCD_DIS_IRQ + SBPCD_STI; return; } @@ -2704,9 +2936,7 @@ for (frame=DriveStruct[d].sbp_current;frame jiffies; timeout--) { @@ -2808,14 +3031,10 @@ { DPRINTF((DBG_INF,"SBPCD: sbp_data: timeout waiting DRV_ATTN - retrying\n")); i=DriveReset(); /* ugly fix to prevent a hang */ -#if SBPCD_DIS_IRQ - sti(); -#endif SBPCD_DIS_IRQ + SBPCD_STI; return (0); } -#if SBPCD_DIS_IRQ - sti(); -#endif SBPCD_DIS_IRQ + SBPCD_STI; } do @@ -2916,7 +3135,12 @@ */ DPRINTF((DBG_LCK,"SBPCD: open_count: %d -> %d\n", DriveStruct[d].open_count,DriveStruct[d].open_count-1)); - if (--DriveStruct[d].open_count==0) yy_LockDoor(0); + if (--DriveStruct[d].open_count==0) + { + do + i=yy_LockDoor(0); + while (i!=0); + } } /*==========================================================================*/ /* @@ -2932,21 +3156,10 @@ sbpcd_ioctl, /* ioctl */ NULL, /* mmap */ sbpcd_open, /* open */ - sbpcd_release /* release */ -}; -/*==========================================================================*/ -/* - * SBP interrupt descriptor - */ -#if SBPCD_USE_IRQ -static struct sigaction sbpcd_sigaction = -{ - sbpcd_interrupt, - 0, - SA_INTERRUPT, - NULL + sbpcd_release, /* release */ + NULL, /* fsync */ + NULL /* fasync */ }; -#endif SBPCD_USE_IRQ /*==========================================================================*/ /* * accept "kernel command line" parameters @@ -2956,6 +3169,8 @@ * sbpcd=0x230,SoundBlaster * or * sbpcd=0x300,LaserMate + * or + * sbpcd=0x330,SPEA * * (upper/lower case sensitive here!!!). * @@ -2966,8 +3181,9 @@ void sbpcd_setup(char *s, int *p) { DPRINTF((DBG_INI,"SBPCD: sbpcd_setup called with %04X,%s\n",p[1], s)); + sbpro_type=0; if (!strcmp(s,str_sb)) sbpro_type=1; - else sbpro_type=0; + else if (!strcmp(s,str_sp)) sbpro_type=2; if (p[0]>0) sbpcd_ioaddr=p[1]; CDo_command=sbpcd_ioaddr; @@ -2986,6 +3202,57 @@ } /*==========================================================================*/ /* + * Sequoia S-1000 CD-ROM Interface Configuration + * as used within SPEA Media FX card + * The SPEA soundcard has to get jumpered for + * -> interface type "Matsushita/Panasonic" (not Sony or Mitsumi) + * -> I/O base address (0x320, 0x330, 0x340, 0x350) + */ +int config_spea(void) +{ + int n_ports=0x10; /* 2:0x00, 8:0x10, 16:0x20, 32:0x30 */ + int irq_number=0; /* 2:0x01, 7:0x03, 12:0x05, 15:0x07, OFF:0x00 */ + int dma_channel=0; /* 0:0x08, 1:0x18, 3:0x38, 5:0x58, 6:0x68, 7:0x78, OFF: 0x00 */ + int dack_polarity=0; /* L:0x00, H:0x80 */ + int drq_polarity=0x40; /* L:0x00, H:0x40 */ + + int i; + +#define SPEA_REG_1 sbpcd_ioaddr+4 +#define SPEA_REG_2 sbpcd_ioaddr+5 + + OUT(SPEA_REG_1,0xFF); + i=inb(SPEA_REG_1); + if (i!=0x0F) + { + DPRINTF((DBG_INF,"SBPCD: no SPEA interface at %04X present.\n", + sbpcd_ioaddr)); + return (-1); /* no interface found */ + } + OUT(SPEA_REG_1,0x04); + OUT(SPEA_REG_2,0xC0); + + OUT(SPEA_REG_1,0x05); + OUT(SPEA_REG_2,0x10|drq_polarity|dack_polarity); + +#if 1 +#define SPEA_PATTERN 0x80 +#else +#define SPEA_PATTERN 0x00 +#endif + OUT(SPEA_REG_1,0x06); + OUT(SPEA_REG_2,dma_channel|irq_number|SPEA_PATTERN); + OUT(SPEA_REG_2,dma_channel|irq_number|SPEA_PATTERN); + + OUT(SPEA_REG_1,0x09); + i=(inb(SPEA_REG_2)&0xCF)|n_ports; + OUT(SPEA_REG_2,i); + + sbpro_type = 0; /* acts like a LaserMate interface now */ + return (0); +} +/*==========================================================================*/ +/* * Test for presence of drive and initialize it. Called at boot time. */ u_long sbpcd_init(u_long mem_start, u_long mem_end) @@ -3006,6 +3273,8 @@ DPRINTF((DBG_WRN,"SBPCD: LILO boot: linux sbpcd=0x230,SoundBlaster\n")); DPRINTF((DBG_WRN,"SBPCD: or like:\n")); DPRINTF((DBG_WRN,"SBPCD: LILO boot: linux sbpcd=0x300,LaserMate\n")); + DPRINTF((DBG_WRN,"SBPCD: or like:\n")); + DPRINTF((DBG_WRN,"SBPCD: LILO boot: linux sbpcd=0x330,SPEA\n")); DPRINTF((DBG_WRN,"SBPCD: \n")); DPRINTF((DBG_WRN,"SBPCD: with your REAL address.\n")); DPRINTF((DBG_WRN,"SBPCD: = = = = = = = = = = END of WARNING = = = = = = = = = =\n")); @@ -3021,13 +3290,19 @@ if (check_region(addr[1],4)) continue; DPRINTF((DBG_INI,"SBPCD: check_region done.\n")); if (autoprobe[port_index+1]==0) type=str_lm; - else type=str_sb; + else if (autoprobe[port_index+1]==1) type=str_sb; + else type=str_sp; sbpcd_setup(type, addr); DPRINTF((DBG_INF,"SBPCD: Trying to detect a %s CD-ROM drive at 0x%X.\n", type, CDo_command)); DPRINTF((DBG_INF,"SBPCD: - ")); sti(); /* to avoid possible "printk" bug */ + if (autoprobe[port_index+1]==2) + { + i=config_spea(); + if (i<0) continue; + } i=check_drives(); DPRINTF((DBG_INI,"SBPCD: check_drives done.\n")); sti(); /* to avoid possible "printk" bug */ @@ -3098,62 +3373,66 @@ if (i>=0) DriveStruct[d].CD_changed=1; } - if (sbpro_type) + if (sbpro_type==1) { OUT(MIXER_addr,MIXER_CD_Volume); OUT(MIXER_data,0xCC); /* one nibble per channel */ } - if (register_blkdev(MATSUSHITA_CDROM_MAJOR, "sbpcd", &sbpcd_fops) != 0) + if (register_blkdev(MAJOR_NR, "sbpcd", &sbpcd_fops) != 0) { - printk("SBPCD: Can't get MAJOR %d for Matsushita CDROM\n", - MATSUSHITA_CDROM_MAJOR); + printk("SBPCD: Can't get MAJOR %d for Matsushita CDROM\n", MAJOR_NR); sti(); /* to avoid possible "printk" bug */ return (mem_start); } - blk_dev[MATSUSHITA_CDROM_MAJOR].request_fn = DEVICE_REQUEST; - read_ahead[MATSUSHITA_CDROM_MAJOR] = 4; /* just one frame */ + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + read_ahead[MAJOR_NR] = SBP_BUFFER_FRAMES * (CD_FRAMESIZE / 512); snarf_region(CDo_command,4); -#if SBPCD_USE_IRQ - if (irqaction(SBPCD_INTR_NR, &sbpcd_sigaction)) + for (j=0;j=NR_SBPCD)) { - printk("SBPCD: media_check: invalid device.\n"); + printk("SBPCD: media_check: invalid device %04X.\n", full_dev); return (-1); } + + switch_drive(MINOR(full_dev)); xx_ReadStatus(); /* command: give 1-byte status */ st=ResponseStatus(); diff -u --recursive --new-file v1.1.17/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v1.1.17/linux/drivers/net/Space.c Tue May 31 12:48:17 1994 +++ linux/drivers/net/Space.c Wed Jun 1 09:40:01 1994 @@ -281,6 +281,14 @@ #define NEXT_DEV (&ppp0_dev) #endif /* PPP */ +#ifdef CONFIG_DUMMY + extern int dummy_init(struct device *dev); + static struct device dummy_dev = { + "dummy", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, dummy_init, }; +# undef NEXT_DEV +# define NEXT_DEV (&dummy_dev) +#endif + #ifdef LOOPBACK extern int loopback_init(struct device *dev); static struct device loopback_dev = { diff -u --recursive --new-file v1.1.17/linux/drivers/net/ppp.c linux/drivers/net/ppp.c --- v1.1.17/linux/drivers/net/ppp.c Tue May 31 12:48:18 1994 +++ linux/drivers/net/ppp.c Thu Jun 2 10:36:43 1994 @@ -94,6 +94,7 @@ int ppp_init(struct device *); static void ppp_init_ctrl_blk(struct ppp *); static int ppp_dev_open(struct device *); +static int ppp_dev_ioctl(struct device *dev, struct ifreq *ifr); static int ppp_dev_close(struct device *); static void ppp_kick_tty(struct ppp *); @@ -264,6 +265,7 @@ dev->mtu = PPP_MTU; dev->hard_start_xmit = ppp_xmit; dev->open = ppp_dev_open; + dev->do_ioctl = ppp_dev_ioctl; dev->stop = ppp_dev_close; dev->get_stats = ppp_get_stats; dev->hard_header = ppp_header; @@ -601,6 +603,32 @@ return 0; } +static int ppp_dev_ioctl(struct device *dev, struct ifreq *ifr) +{ + struct ppp *ppp = &ppp_ctrl[dev->base_addr]; + int error; + + struct stats + { + struct ppp_stats ppp_stats; + struct slcompress slhc; + } *result; + + error = verify_area (VERIFY_READ, + ifr->ifr_ifru.ifru_data, + sizeof (struct stats)); + + if (error == 0) { + result = (struct stats *) ifr->ifr_ifru.ifru_data; + + memcpy_tofs (&result->ppp_stats, &ppp->stats, sizeof (struct ppp_stats)); + if (ppp->slcomp) + memcpy_tofs (&result->slhc, ppp->slcomp, sizeof (struct slcompress)); + } + + return error; +} + /************************************************************* * TTY OUTPUT * The following function delivers a fully-formed PPP @@ -882,6 +910,8 @@ if (ppp_debug >= 5) { ppp_print_buffer ("receive buffer", cp, count, KERNEL_DS); } + + ppp->stats.rbytes += count; while (count-- > 0) { c = *cp++; @@ -1367,7 +1397,7 @@ PRINTKN (3,(KERN_INFO "ppp_ioctl: set mru to %x\n", temp_i)); temp_i = (int) get_fs_long (l); if (ppp->mru != temp_i) - ppp_changedmtu (ppp, ppp->mtu, temp_i); + ppp_changedmtu (ppp, ppp->dev->mtu, temp_i); } break; diff -u --recursive --new-file v1.1.17/linux/drivers/scsi/buslogic.c linux/drivers/scsi/buslogic.c --- v1.1.17/linux/drivers/scsi/buslogic.c Fri May 27 10:49:08 1994 +++ linux/drivers/scsi/buslogic.c Thu Jun 2 10:22:04 1994 @@ -562,7 +562,6 @@ if (bufflen != sizeof SCpnt->sense_buffer) { buslogic_printk("Wrong buffer length supplied for request sense (%d)\n", bufflen); - panic("buslogic.c: wrong buffer length for request sense"); } #endif SCpnt->result = 0; @@ -781,6 +780,7 @@ buslogic_printk("buslogic_detect: failed setting up mailboxes\n"); } ok = TRUE; + return ok; must_be_adaptec: INTR_RESET(base); printk("- must be Adaptec\n"); /* So that the adaptec detect looks clean */ @@ -888,7 +888,6 @@ /* Query the board to find out the model. */ static int buslogic_query(unsigned int base, int *trans) { -#if 0 unsigned const char inquiry_cmd[] = { CMD_INQUIRY }; unsigned char inquiry_result[4]; int i; @@ -899,14 +898,18 @@ buslogic_out(base, inquiry_cmd, sizeof inquiry_cmd); buslogic_in(base, inquiry_result, 4); WAIT_UNTIL(INTERRUPT(base), CMDC); + INTR_RESET(base); + + buslogic_printk("Inquiry Bytes: %X %X %X %X\n", + inquiry_result[0],inquiry_result[1], + inquiry_result[2],inquiry_result[3]); while (0) { fail: - buslogic_printk("buslogic_detect: query card type\n"); + buslogic_printk("buslogic_query: query board settings\n"); + return TRUE; } - INTR_RESET(base); -#endif - *trans = BIOS_TRANSLATION_6432; /* Default case */ + *trans = BIOS_TRANSLATION_6432; /* Default case */ return FALSE; } @@ -1018,8 +1021,13 @@ host[irq - 9] = SHpnt; SHpnt->this_id = id; +#ifdef CONFIG_NO_BUGGY_BUSLOGIC /* Only type 'A' (AT/ISA) bus adapters use unchecked DMA. */ SHpnt->unchecked_isa_dma = (bus_type == 'A'); +#else + /* bugs in the firmware with 16M+. Gaah */ + SHpnt->unchecked_isa_dma = 1; +#endif SHpnt->sg_tablesize = max_sg; if (SHpnt->sg_tablesize > BUSLOGIC_MAX_SG) SHpnt->sg_tablesize = BUSLOGIC_MAX_SG; diff -u --recursive --new-file v1.1.17/linux/fs/buffer.c linux/fs/buffer.c --- v1.1.17/linux/fs/buffer.c Mon May 23 12:14:24 1994 +++ linux/fs/buffer.c Thu Jun 2 10:33:28 1994 @@ -44,6 +44,9 @@ #ifdef CONFIG_MCD extern int check_mcd_media_change(int, int); #endif +#ifdef CONFIG_SBPCD +extern int check_sbpcd_media_change(int, int); +#endif #define NR_SIZES 4 static char buffersize_index[9] = {-1, 0, 1, -1, 2, -1, -1, -1, 3}; @@ -331,6 +334,12 @@ #if defined(CONFIG_MCD) case MITSUMI_CDROM_MAJOR: i = check_mcd_media_change(dev, 0); + break; +#endif + +#if defined(CONFIG_SBPCD) + case MATSUSHITA_CDROM_MAJOR: + i = check_sbpcd_media_change(dev, 0); break; #endif Only in v1.1.17/linux/include/linux: mktime.h diff -u --recursive --new-file v1.1.17/linux/include/linux/sbpcd.h linux/include/linux/sbpcd.h --- v1.1.17/linux/include/linux/sbpcd.h Tue May 31 12:48:19 1994 +++ linux/include/linux/sbpcd.h Thu Jun 2 10:33:28 1994 @@ -8,6 +8,8 @@ * sbpcd=0x230,SoundBlaster * or * sbpcd=0x300,LaserMate + * or + * sbpcd=0x330,SPEA * these strings are case sensitive !!! */ @@ -17,6 +19,7 @@ * set SBPRO to 1 for "true" SoundBlaster card * set SBPRO to 0 for "poor" (no sound) interface cards * and for "compatible" soundcards. + * set SBPRO to 2 for the SPEA Media FX card * * most "compatible" sound boards like Galaxy need to set SBPRO to 0 !!! * if SBPRO gets set wrong, the drive will get found - but any @@ -33,6 +36,7 @@ * put your CDROM port base address here: * SBPRO addresses typically are 0x0230 (=0x220+0x10), 0x0250, ... * LASERMATE (CI-101P) adresses typically are 0x0300, 0x0310, ... + * SPEA addresses are 0x320, 0x330, 0x340, 0x350 * there are some soundcards on the market with 0x0630, 0x0650, ... * * example: if your SBPRO audio address is 0x220, specify 0x230. @@ -52,7 +56,7 @@ * Debug output levels */ #define DBG_INF 1 /* necessary information */ -#define DBG_IRQ 2 /* interrupt trace */ +#define DBG_BSZ 2 /* BLOCK_SIZE trace */ #define DBG_REA 3 /* "read" status trace */ #define DBG_CHK 4 /* "media check" trace */ #define DBG_TIM 5 /* datarate timer test */ @@ -75,7 +79,8 @@ #define DBG_XA 22 /* XA mode debugging */ #define DBG_LCK 23 /* door (un)lock info */ #define DBG_SQ 24 /* dump SubQ frame */ -#define DBG_000 25 /* unnecessary information */ +#define DBG_AUD 25 /* "read audio" debugging */ +#define DBG_000 26 /* unnecessary information */ /*==========================================================================*/ /*==========================================================================*/ @@ -199,8 +204,18 @@ #define READ_M1 0x01 /* "data mode 1": 2048 bytes per frame */ #define READ_M2 0x02 /* "data mode 2": 12+2048+280 bytes per frame */ #define READ_SC 0x04 /* "subchannel info": 96 bytes per frame */ +#define READ_AU 0x08 /* "audio frame": 2352 bytes per frame */ /* + * preliminary extensions to cdrom.h for transfering audio frames: + */ +#define CDROMREADAUDIO 0xE0 /* IOCTL function (arg = &cdrom_aud) */ + +struct cdrom_aud { u_int lba; /* frame address */ + u_char *buf; /* frame buffer (2352 bytes) */ + }; + +/* * sense byte: used only if new_drive * only during cmd 09 00 xx ah al 00 00 * @@ -401,17 +416,6 @@ #define SBPCD_DIS_IRQ 0 /* - * we don't use the IRQ line - leave it free for the sound driver - */ -#define SBPCD_USE_IRQ 0 - -/* - * you can set the interrupt number of your interface board here: - * It is not used at this time. No need to set it correctly. - */ -#define SBPCD_INTR_NR 7 - -/* * "write byte to port" */ #define OUT(x,y) outb(y,x) @@ -463,9 +467,3 @@ BLK; /*==========================================================================*/ - - - - - - diff -u --recursive --new-file v1.1.17/linux/kernel/Makefile linux/kernel/Makefile --- v1.1.17/linux/kernel/Makefile Tue May 24 00:34:58 1994 +++ linux/kernel/Makefile Thu Jun 2 10:43:14 1994 @@ -18,7 +18,7 @@ OBJS = sched.o sys_call.o traps.o irq.o dma.o fork.o \ panic.o printk.o vsprintf.o sys.o module.o ksyms.o exit.o \ - signal.o mktime.o ptrace.o ioport.o itimer.o \ + signal.o ptrace.o ioport.o itimer.o \ info.o ldt.o time.o tqueue.o vm86.o all: kernel.o Only in v1.1.17/linux/kernel: mktime.c diff -u --recursive --new-file v1.1.17/linux/kernel/sched.c linux/kernel/sched.c --- v1.1.17/linux/kernel/sched.c Fri May 27 10:49:15 1994 +++ linux/kernel/sched.c Thu Jun 2 10:37:53 1994 @@ -517,6 +517,8 @@ if (xtime.tv_sec > last_rtc_update + 660) if (set_rtc_mmss(xtime.tv_sec) == 0) last_rtc_update = xtime.tv_sec; + else + last_rtc_update = xtime.tv_sec - 600; /* do it again in one min */ } /* diff -u --recursive --new-file v1.1.17/linux/kernel/time.c linux/kernel/time.c --- v1.1.17/linux/kernel/time.c Mon Jan 31 09:01:36 1994 +++ linux/kernel/time.c Thu Jun 2 10:54:37 1994 @@ -14,6 +14,8 @@ * Created file with time related functions from sched.c and adjtimex() * 08 Oct 93 Torsten Duwe * adjtime interface update and CMOS clock write code + * 02 Jul 94 Alan Modra + * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime */ #include @@ -32,12 +34,36 @@ #include extern struct timeval xtime; -#include -extern long kernel_mktime(struct mktime * time); +/* converts date to days since 1/1/1970 + * assumes year,mon,day in normal date format + * ie. 1/1/1970 => year=1970, mon=1, day=1 + * + * For the Julian calendar (which was used in Russia before 1917, + * Britain & colonies before 1752, anywhere else before 1582, + * and is still in use by some communities) leave out the + * -year/100+year/400 terms, and add 10. + * + * This algorithm was first published by Gauss (I think). + */ +static inline unsigned long mktime(unsigned int year, unsigned int mon, + unsigned int day, unsigned int hour, + unsigned int min, unsigned int sec) +{ + if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ + mon += 12; /* Puts Feb last since it has leap day */ + year -= 1; + } + return ((( + (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + + year*365 - 719499 + )*24 + hour /* now have hours */ + )*60 + min /* now have minutes */ + )*60 + sec; /* finally seconds */ +} void time_init(void) { - struct mktime time; + unsigned int year, mon, day, hour, min, sec; int i; /* checking for Update-In-Progress could be done more elegantly @@ -53,25 +79,26 @@ if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) break; do { /* Isn't this overkill ? UIP above should guarantee consistency */ - time.sec = CMOS_READ(RTC_SECONDS); - time.min = CMOS_READ(RTC_MINUTES); - time.hour = CMOS_READ(RTC_HOURS); - time.day = CMOS_READ(RTC_DAY_OF_MONTH); - time.mon = CMOS_READ(RTC_MONTH); - time.year = CMOS_READ(RTC_YEAR); - } while (time.sec != CMOS_READ(RTC_SECONDS)); + sec = CMOS_READ(RTC_SECONDS); + min = CMOS_READ(RTC_MINUTES); + hour = CMOS_READ(RTC_HOURS); + day = CMOS_READ(RTC_DAY_OF_MONTH); + mon = CMOS_READ(RTC_MONTH); + year = CMOS_READ(RTC_YEAR); + } while (sec != CMOS_READ(RTC_SECONDS)); if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { - BCD_TO_BIN(time.sec); - BCD_TO_BIN(time.min); - BCD_TO_BIN(time.hour); - BCD_TO_BIN(time.day); - BCD_TO_BIN(time.mon); - BCD_TO_BIN(time.year); + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); } - time.mon--; - xtime.tv_sec = kernel_mktime(&time); - } + if ((year += 1900) < 1970) + year += 100; + xtime.tv_sec = mktime(year, mon, day, hour, min, sec); +} /* * The timezone where the local system is located. Used as a default by some * programs who obtain this value by using gettimeofday. @@ -403,8 +430,8 @@ int set_rtc_mmss(unsigned long nowtime) { int retval = 0; - short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; - unsigned char save_control, save_freq_select, cmos_minutes; + int real_seconds, real_minutes, cmos_minutes; + unsigned char save_control, save_freq_select; save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); @@ -419,11 +446,15 @@ /* since we're only adjusting minutes and seconds, * don't interfere with hour overflow. This avoids * messing with unknown time zones but requires your - * RTC not to be off by more than 30 minutes + * RTC not to be off by more than 15 minutes */ - if (((cmos_minutes < real_minutes) ? - (real_minutes - cmos_minutes) : - (cmos_minutes - real_minutes)) < 30) + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) + real_minutes += 30; /* correct for half hour time zone */ + real_minutes %= 60; + + if (abs(real_minutes - cmos_minutes) < 30) { if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { diff -u --recursive --new-file v1.1.17/linux/mm/memory.c linux/mm/memory.c --- v1.1.17/linux/mm/memory.c Sat May 7 14:54:17 1994 +++ linux/mm/memory.c Thu Jun 2 12:36:00 1994 @@ -46,6 +46,13 @@ #include #include +/* + * Define this if things work differently on a i386 and a i486: + * it will (on a i486) warn about kernel memory accesses that are + * done without a 'verify_area(VERIFY_WRITE,..)' + */ +#undef CONFIG_TEST_VERIFY_AREA + unsigned long high_memory = 0; extern unsigned long pg0[1024]; /* page table for 0-4MB for everybody */ @@ -902,10 +909,15 @@ } else user_esp = regs->esp; } - if (error_code & PAGE_PRESENT) + if (error_code & PAGE_PRESENT) { +#ifdef CONFIG_TEST_VERIFY_AREA + if (regs->cs == KERNEL_CS) + printk("WP fault at %08x\n", regs->eip); +#endif do_wp_page(error_code, address, current, user_esp); - else + } else { do_no_page(error_code, address, current, user_esp); + } return; } address -= TASK_SIZE; @@ -1124,6 +1136,9 @@ invalidate(); if (wp_works_ok < 0) wp_works_ok = 0; +#ifdef CONFIG_TEST_VERIFY_AREA + wp_works_ok = 0; +#endif return; } diff -u --recursive --new-file v1.1.17/linux/net/inet/af_inet.c linux/net/inet/af_inet.c --- v1.1.17/linux/net/inet/af_inet.c Tue May 24 00:35:00 1994 +++ linux/net/inet/af_inet.c Thu Jun 2 11:18:51 1994 @@ -1137,7 +1137,7 @@ return -EINVAL; if(size==0) return 0; - err=verify_area(VERIFY_READ,ubuf,size); + err=verify_area(VERIFY_WRITE,ubuf,size); if(err) return err; @@ -1259,6 +1259,8 @@ case SIOCSIFMAP: case SIOCGIFMAP: case SIOCDEVPRIVATE: + case SIOCSIFSLAVE: + case SIOCGIFSLAVE: return(dev_ioctl(cmd,(void *) arg)); default: diff -u --recursive --new-file v1.1.17/linux/net/inet/arp.c linux/net/inet/arp.c --- v1.1.17/linux/net/inet/arp.c Thu Jun 2 13:50:55 1994 +++ linux/net/inet/arp.c Thu Jun 2 10:36:43 1994 @@ -26,6 +26,7 @@ * Alan Cox : Make ARP add its own protocol entry * * Ross Martin : Rewrote arp_rcv() and arp_get_info() + * Stephen Henson : Add AX25 support to arp_get_info() */ #include @@ -846,6 +847,13 @@ /* * Convert hardware address to XX:XX:XX:XX ... form. */ +#ifdef CONFIG_AX25 + + if(entry->htype==ARPHRD_AX25) + strcpy(hbuffer,ax2asc((ax25_address *)entry->ha)); + else { +#endif + for(k=0,j=0;khlen;j++) { hbuffer[k++]=hexbuf[ (entry->ha[j]>>4)&15 ]; @@ -854,6 +862,9 @@ } hbuffer[--k]=0; +#ifdef CONFIG_AX25 + } +#endif size = sprintf(buffer+len, "%-17s0x%-10x0x%-10x%s\n", in_ntoa(entry->ip), @@ -926,9 +937,6 @@ */ switch (r.arp_ha.sa_family) { - case 0: - /* Moan about this. ARP family 0 is NetROM and _will_ be needed */ - printk("Application using old BSD convention for arp set. Please recompile it.\n"); case ARPHRD_ETHER: htype = ARPHRD_ETHER; hlen = ETH_ALEN; diff -u --recursive --new-file v1.1.17/linux/net/inet/dev.c linux/net/inet/dev.c --- v1.1.17/linux/net/inet/dev.c Tue May 31 12:48:20 1994 +++ linux/net/inet/dev.c Thu Jun 2 10:36:44 1994 @@ -1267,7 +1267,7 @@ return -ENODEV; } cli(); - if(slave->flags&(IFF_UP|IFF_RUNNING)!=(IFF_UP|IFF_RUNNING)) + if((slave->flags&(IFF_UP|IFF_RUNNING))!=(IFF_UP|IFF_RUNNING)) { restore_flags(flags); return -EINVAL; @@ -1275,7 +1275,7 @@ if(dev->flags&IFF_SLAVE) { restore_flags(flags); - return -EINVAL; + return -EBUSY; } if(dev->slave!=NULL) { diff -u --recursive --new-file v1.1.17/linux/net/inet/ip.c linux/net/inet/ip.c --- v1.1.17/linux/net/inet/ip.c Thu Jun 2 13:50:56 1994 +++ linux/net/inet/ip.c Wed Jun 1 10:14:57 1994 @@ -90,6 +90,7 @@ extern void sort_send(struct sock *sk); #define min(a,b) ((a)<(b)?(a):(b)) +#define LOOPBACK(x) (((x) & htonl(0xff000000)) == htonl(0x7f000000)) /* * SNMP management statistics @@ -226,7 +227,7 @@ * If the frame is from us and going off machine it MUST MUST MUST * have the output device ip address and never the loopback */ - if (saddr == htonl(0x7F000001L) && daddr != htonl(0x7F000001L)) + if (LOOPBACK(saddr) && !LOOPBACK(daddr)) saddr = src;/*rt->rt_dev->pa_addr;*/ raddr = rt->rt_gateway; @@ -245,7 +246,7 @@ * If the frame is from us and going off machine it MUST MUST MUST * have the output device ip address and never the loopback */ - if (saddr == 0x0100007FL && daddr != 0x0100007FL) + if (LOOPBACK(saddr) && !LOOPBACK(daddr)) saddr = src;/*rt->rt_dev->pa_addr;*/ raddr = (rt == NULL) ? 0 : rt->rt_gateway;