Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
893c4d2f
Commit
893c4d2f
authored
Nov 23, 2007
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Import 1.1.18
parent
9ec7e58c
Changes
41
Show whitespace changes
Inline
Side-by-side
Showing
41 changed files
with
2029 additions
and
1471 deletions
+2029
-1471
Makefile
Makefile
+1
-1
drivers/FPU-emu/Makefile
drivers/FPU-emu/Makefile
+1
-2
drivers/FPU-emu/README
drivers/FPU-emu/README
+16
-6
drivers/FPU-emu/errors.c
drivers/FPU-emu/errors.c
+53
-31
drivers/FPU-emu/fpu_arith.c
drivers/FPU-emu/fpu_arith.c
+22
-22
drivers/FPU-emu/fpu_aux.c
drivers/FPU-emu/fpu_aux.c
+17
-18
drivers/FPU-emu/fpu_emu.h
drivers/FPU-emu/fpu_emu.h
+30
-29
drivers/FPU-emu/fpu_entry.c
drivers/FPU-emu/fpu_entry.c
+137
-113
drivers/FPU-emu/fpu_etc.c
drivers/FPU-emu/fpu_etc.c
+21
-19
drivers/FPU-emu/fpu_proto.h
drivers/FPU-emu/fpu_proto.h
+27
-24
drivers/FPU-emu/fpu_system.h
drivers/FPU-emu/fpu_system.h
+24
-12
drivers/FPU-emu/fpu_trig.c
drivers/FPU-emu/fpu_trig.c
+279
-267
drivers/FPU-emu/get_address.c
drivers/FPU-emu/get_address.c
+175
-92
drivers/FPU-emu/load_store.c
drivers/FPU-emu/load_store.c
+191
-168
drivers/FPU-emu/poly_atan.c
drivers/FPU-emu/poly_atan.c
+0
-8
drivers/FPU-emu/reg_compare.c
drivers/FPU-emu/reg_compare.c
+38
-39
drivers/FPU-emu/reg_constant.c
drivers/FPU-emu/reg_constant.c
+1
-1
drivers/FPU-emu/reg_div.S
drivers/FPU-emu/reg_div.S
+4
-4
drivers/FPU-emu/reg_ld_str.c
drivers/FPU-emu/reg_ld_str.c
+202
-232
drivers/FPU-emu/reg_round.S
drivers/FPU-emu/reg_round.S
+6
-6
drivers/FPU-emu/reg_u_div.S
drivers/FPU-emu/reg_u_div.S
+4
-4
drivers/FPU-emu/reg_u_mul.S
drivers/FPU-emu/reg_u_mul.S
+4
-4
drivers/FPU-emu/version.h
drivers/FPU-emu/version.h
+1
-2
drivers/FPU-emu/wm_sqrt.S
drivers/FPU-emu/wm_sqrt.S
+4
-4
drivers/block/README.sbpcd
drivers/block/README.sbpcd
+147
-129
drivers/block/blk.h
drivers/block/blk.h
+3
-0
drivers/block/ll_rw_blk.c
drivers/block/ll_rw_blk.c
+0
-4
drivers/block/sbpcd.c
drivers/block/sbpcd.c
+447
-168
drivers/net/Space.c
drivers/net/Space.c
+8
-0
drivers/net/ppp.c
drivers/net/ppp.c
+31
-1
drivers/scsi/buslogic.c
drivers/scsi/buslogic.c
+14
-6
fs/buffer.c
fs/buffer.c
+9
-0
include/linux/sbpcd.h
include/linux/sbpcd.h
+17
-19
kernel/Makefile
kernel/Makefile
+1
-1
kernel/sched.c
kernel/sched.c
+2
-0
kernel/time.c
kernel/time.c
+56
-25
mm/memory.c
mm/memory.c
+17
-2
net/inet/af_inet.c
net/inet/af_inet.c
+3
-1
net/inet/arp.c
net/inet/arp.c
+11
-3
net/inet/dev.c
net/inet/dev.c
+2
-2
net/inet/ip.c
net/inet/ip.c
+3
-2
No files found.
Makefile
View file @
893c4d2f
VERSION
=
1
PATCHLEVEL
=
1
SUBLEVEL
=
1
7
SUBLEVEL
=
1
8
all
:
Version zImage
...
...
drivers/FPU-emu/Makefile
View file @
893c4d2f
...
...
@@ -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
$<
...
...
drivers/FPU-emu/README
View file @
893c4d2f
...
...
@@ -47,7 +47,7 @@ Please report bugs, etc to me at:
--Bill Metzenthen
March
1994
June
1994
----------------------- Internals of wm-FPU-emu -----------------------
...
...
@@ -80,20 +80,24 @@ emulate each FPU instruction to completion without interruption.
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 th
e
more
important differences are listed below:
(version
1.12) and the 80486 FPU (apart from bugs). Some of the mor
e
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 @@ crashes dosemu under Linux and also brings Windows down with a general
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 @@ Hamish Coleman, t933093@minyos.xx.rmit.oz.au
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.
...
...
drivers/FPU-emu/errors.c
View file @
893c4d2f
...
...
@@ -42,6 +42,8 @@ void Un_impl(void)
RE_ENTRANT_CHECK_OFF
;
/* No need to verify_area(), we have previously fetched these bytes. */
printk
(
"Unimplemented FPU Opcode at eip=%p : "
,
(
void
*
)
address
);
if
(
FPU_CS
==
USER_CS
)
{
while
(
1
)
{
byte1
=
get_fs_byte
((
unsigned
char
*
)
address
);
...
...
@@ -56,6 +58,12 @@ void Un_impl(void)
printk
(
"%02x (%02x+%d)
\n
"
,
FPU_modrm
,
FPU_modrm
&
0xf8
,
FPU_modrm
&
7
);
else
printk
(
"/%d
\n
"
,
(
FPU_modrm
>>
3
)
&
7
);
}
else
{
printk
(
"cs selector = %04x
\n
"
,
FPU_CS
);
}
RE_ENTRANT_CHECK_ON
;
EXCEPTION
(
EX_Invalid
);
...
...
@@ -85,6 +93,8 @@ void emu_printall()
RE_ENTRANT_CHECK_OFF
;
/* No need to verify_area(), we have previously fetched these bytes. */
printk
(
"At %p:"
,
(
void
*
)
address
);
if
(
FPU_CS
==
USER_CS
)
{
#define MAX_PRINTED_BYTES 20
for
(
i
=
0
;
i
<
MAX_PRINTED_BYTES
;
i
++
)
{
...
...
@@ -109,6 +119,11 @@ void emu_printall()
printk
(
" /%d, mod=%d rm=%d
\n
"
,
(
FPU_modrm
>>
3
)
&
7
,
(
FPU_modrm
>>
6
)
&
3
,
FPU_modrm
&
7
);
}
}
else
{
printk
(
"%04x
\n
"
,
FPU_CS
);
}
partial_status
=
status_word
();
...
...
@@ -181,6 +196,7 @@ printk(" CW: ic=%d rc=%ld%ld pc=%ld%ld iem=%d ef=%d%d%d%d%d%d\n",
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 @@ printk(" CW: ic=%d rc=%ld%ld pc=%ld%ld iem=%d ef=%d%d%d%d%d%d\n",
(
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 @@ static struct {
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 @@ static struct {
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 @@ void stack_overflow(void)
{
/* 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 @@ void stack_underflow(void)
if
(
control_word
&
CW_Invalid
)
{
/* The masked response */
reg_move
(
&
CONST_QNaN
,
FPU_st0_ptr
);
reg_move
(
&
CONST_QNaN
,
&
st
(
0
)
);
}
EXCEPTION
(
EX_StackUnder
);
...
...
drivers/FPU-emu/fpu_arith.c
View file @
893c4d2f
...
...
@@ -20,7 +20,7 @@ void fadd__()
{
/* 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 @@ void fmul__()
{
/* 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 @@ void fsub__()
{
/* 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 @@ void fsubr_()
{
/* 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 @@ void fdiv__()
{
/* 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 @@ void fdivr_()
{
/* 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 @@ void fadd_i()
{
/* 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 @@ void fmul_i()
{
/* 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 @@ void fsubri()
{
/* 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 @@ void fsub_i()
{
/* 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 @@ void fdivri()
{
/* 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 @@ void fdiv_i()
{
/* 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 @@ void faddp_()
{
/* 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 @@ void fmulp_()
{
/* 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 @@ void fsubrp()
{
/* 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 @@ void fsubp_()
{
/* 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 @@ void fdivrp()
{
/* 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 @@ void fdivp_()
{
/* 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
();
}
drivers/FPU-emu/fpu_aux.c
View file @
893c4d2f
...
...
@@ -26,8 +26,7 @@ void fclex(void)
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 @@ void finit()
}
/* 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 @@ void finit_()
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 @@ void fld_i_()
{
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 @@ void fxch_i()
{
/* 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 @@ void fxch_i()
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 ffreep()
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
();
}
drivers/FPU-emu/fpu_emu.h
View file @
893c4d2f
...
...
@@ -60,14 +60,18 @@
#include <linux/math_emu.h>
#include <linux/linkage.h>
#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 @@ extern char emulating;
#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) { \
...
...
drivers/FPU-emu/fpu_entry.c
View file @
893c4d2f
...
...
@@ -122,39 +122,36 @@ static unsigned char const type_table[64] = {
#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
;
#ifdef PARANOID
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 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 @@ asmlinkage void math_emulate(long arg)
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
)
{
/* user code space? */
if
(
FPU_CS
==
KERNEL_CS
)
/* 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
)
{
printk
(
"math_emulate: %04x:%08lx
\n
"
,
FPU_CS
,
FPU_EIP
);
panic
(
"Math emulation needed in kernel"
);
}
else
{
/* We cannot handle multiple segments yet */
if
(
FPU_CS
!=
USER_CS
||
FPU_DS
!=
USER_DS
)
if
(
(
FPU_CS
&
4
)
!=
4
)
/* Must be in the LDT */
{
math_abort
(
FPU_info
,
SIGILL
);
/* 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
);
}
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
{
/* 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 @@ asmlinkage void math_emulate(long arg)
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 @@ asmlinkage void math_emulate(long arg)
* 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 @@ asmlinkage void math_emulate(long arg)
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 @@ asmlinkage void math_emulate(long arg)
}
}
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 @@ asmlinkage void math_emulate(long arg)
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 @@ asmlinkage void math_emulate(long arg)
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 @@ asmlinkage void math_emulate(long arg)
{
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 @@ asmlinkage void math_emulate(long arg)
else
stack_underflow
();
}
reg_mem_instr_done:
operand_address
=
data_sel_off
;
}
else
{
if
(
!
(
no_ip_update
=
load_store_instr
(((
FPU_modrm
&
0x38
)
|
(
byte1
&
6
))
>>
1
,
addr_modes
);
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 @@ asmlinkage void math_emulate(long arg)
#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_
ST
0
)
{
stack_underflow
();
goto
FPU_instruction_done
;
}
break
;
case
_REGIi
:
if
(
!
NOT_EMPTY_0
||
!
NOT_EMPTY
(
FPU_rm
)
)
if
(
!
NOT_EMPTY_
ST
0
||
!
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_
ST
0
||
!
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_
ST
0
||
!
NOT_EMPTY
(
FPU_rm
)
)
{
stack_underflow
();
goto
FPU_instruction_done
;
...
...
@@ -532,16 +561,13 @@ asmlinkage void math_emulate(long arg)
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:
...
...
@@ -553,16 +579,14 @@ asmlinkage void math_emulate(long arg)
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
;
}
...
...
drivers/FPU-emu/fpu_etc.c
View file @
893c4d2f
...
...
@@ -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 fabs(void)
}
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 @@ static void ftst_(void)
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 ftst_(void)
}
}
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 @@ static void fxam(void)
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 @@ static void fxam(void)
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
)
);
}
drivers/FPU-emu/fpu_proto.h
View file @
893c4d2f
...
...
@@ -63,13 +63,16 @@ extern void trig_a(void);
extern
void
trig_b
(
void
);
/* get_address.c */
extern
void
get_address
(
unsigned
char
FPU_modrm
,
unsigned
long
*
fpu_eip
,
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
,
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 @@ extern int reg_sub(FPU_REG const *a, FPU_REG const *b,
/* 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 fucompp(void);
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
,
...
...
drivers/FPU-emu/fpu_system.h
View file @
893c4d2f
...
...
@@ -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)
...
...
@@ -64,7 +79,4 @@
#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
drivers/FPU-emu/fpu_trig.c
View file @
893c4d2f
...
...
@@ -166,16 +166,16 @@ void convert_l2reg(long const *arg, FPU_REG *dest)
}
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_error(void)
}
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 @@ static void single_arg_2_error(void)
/* 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 single_arg_2_error(void)
/*---------------------------------------------------------------------------*/
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 @@ static void f2xm1(void)
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 @@ static void fptan(void)
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 @@ static void fptan(void)
/* 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 @@ static void fptan(void)
/* 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 fxtract(void)
}
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 @@ static void fsin(void)
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 @@ static void fsin(void)
/* 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 @@ static void fsin(void)
/* 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 @@ static int f_cos(FPU_REG *arg)
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 @@ static void fsincos(void)
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 @@ static void rem_kernel(unsigned long long st0, unsigned long long *y,
/* 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 @@ static void do_fprem(int round)
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 @@ static void do_fprem(int round)
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 @@ static void do_fprem(int round)
}
else
{
reg_move
(
FPU_
st0_ptr
,
&
tmp
);
reg_move
(
st0_ptr
,
&
tmp
);
q
=
0
;
}
tmp
.
sign
=
sign
;
...
...
@@ -858,7 +866,7 @@ static void do_fprem(int round)
/* 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 @@ static void do_fprem(int round)
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 @@ static void do_fprem(int round)
/* 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 @@ static void do_fprem(int round)
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 @@ static void do_fprem(int round)
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 @@ static void do_fprem(int round)
}
}
}
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 @@ static void do_fprem(int round)
/* 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 @@ static void fyl2x(void)
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 @@ static void fyl2x(void)
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 @@ static void fyl2x(void)
/* 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 @@ static void fyl2x(void)
/* 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 @@ static void fyl2x(void)
}
#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 @@ static void fyl2x(void)
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 @@ static void fyl2x(void)
/* 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 @@ static void fyl2x(void)
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 fyl2x(void)
}
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 @@ static void fpatan(void)
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 @@ static void fpatan(void)
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 @@ static void fpatan(void)
}
#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 @@ static void fpatan(void)
{
/* 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 @@ static void fpatan(void)
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 fpatan(void)
}
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 @@ static void fyl2xp1(void)
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 @@ static void fyl2xp1(void)
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 @@ static void fyl2xp1(void)
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 @@ static void fyl2xp1(void)
}
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 @@ static void fyl2xp1(void)
#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 @@ static void fyl2xp1(void)
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 @@ static void fyl2xp1(void)
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 fyl2xp1(void)
}
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 @@ static void fscale(void)
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 @@ static void fscale(void)
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 @@ static void fscale(void)
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 @@ static void fscale(void)
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 @@ static void fscale(void)
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 void fscale(void)
/*---------------------------------------------------------------------------*/
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
)
);
}
drivers/FPU-emu/get_address.c
View file @
893c4d2f
...
...
@@ -19,6 +19,7 @@
#include <linux/stddef.h>
#include <linux/head.h>
#include <asm/segment.h>
...
...
@@ -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 @@ static int reg_offset_vm86[] = {
#define VM86_REG_(x) (*(unsigned short *) \
(reg_offset_vm86[((unsigned)x)]+(char *) FPU_info))
static
int
reg_offset_p
286
[]
=
{
static
int
reg_offset_p
m
[]
=
{
offsetof
(
struct
info
,
___cs
),
offsetof
(
struct
info
,
___ds
),
offsetof
(
struct
info
,
___es
),
...
...
@@ -62,12 +66,12 @@ static int reg_offset_p286[] = {
offsetof
(
struct
info
,
___ds
)
};
#define P
286
_REG_(x) (*(unsigned short *) \
(reg_offset_p
286
[((unsigned)x)]+(char *) FPU_info))
#define P
M
_REG_(x) (*(unsigned short *) \
(reg_offset_p
m
[((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 @@ static void *sib(int mod, unsigned long *fpu_eip)
(
*
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 @@ static unsigned long mode16_segment(fpu_addr_modes addr_modes)
math_abort
(
FPU_info
,
SIGSEGV
);
}
#endif PARANOID
if
(
addr_modes
.
vm86
)
*
selector
=
VM86_REG_
(
segment
);
return
(
unsigned
long
)
VM86_REG_
(
segment
)
<<
4
;
else
if
(
addr_modes
.
p286
)
return
(
unsigned
long
)
LDT_BASE_ADDR
(
P286_REG_
(
segment
));
return
0
;
}
/* 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,61 +211,61 @@ static unsigned long mode16_segment(fpu_addr_modes addr_modes)
*/
void
get_address
(
unsigned
char
FPU_modrm
,
unsigned
long
*
fpu_eip
,
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
);
else
{
cpu_reg_ptr
=
&
REG_
(
rm
);
switch
(
mod
)
{
case
0
:
if
(
FPU_
rm
==
5
)
if
(
rm
==
5
)
{
/* Special case: disp32 */
RE_ENTRANT_CHECK_OFF
;
FPU_code_verify_area
(
4
);
offset
=
get_fs_long
((
unsigned
long
*
)
(
*
fpu_eip
));
address
=
get_fs_long
((
unsigned
long
*
)
(
*
fpu_eip
));
(
*
fpu_eip
)
+=
4
;
RE_ENTRANT_CHECK_ON
;
FPU_data_address
=
(
void
*
)
offset
;
return
;
addr
->
offset
=
address
;
return
(
void
*
)
address
;
}
else
{
FPU_data_address
=
(
void
*
)
*
cpu_reg_ptr
;
/* Just return the contents
address
=
*
cpu_reg_ptr
;
/* Just return the contents
of the cpu register */
return
;
addr
->
offset
=
address
;
return
(
void
*
)
address
;
}
case
1
:
/* 8 bit signed displacement */
RE_ENTRANT_CHECK_OFF
;
FPU_code_verify_area
(
1
);
offset
=
(
signed
char
)
get_fs_byte
((
char
*
)
(
*
fpu_eip
));
address
=
(
signed
char
)
get_fs_byte
((
char
*
)
(
*
fpu_eip
));
RE_ENTRANT_CHECK_ON
;
(
*
fpu_eip
)
++
;
break
;
...
...
@@ -219,7 +273,7 @@ void get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
/* 32 bit displacement */
RE_ENTRANT_CHECK_OFF
;
FPU_code_verify_area
(
4
);
offset
=
(
signed
)
get_fs_long
((
unsigned
long
*
)
(
*
fpu_eip
));
address
=
(
signed
)
get_fs_long
((
unsigned
long
*
)
(
*
fpu_eip
));
(
*
fpu_eip
)
+=
4
;
RE_ENTRANT_CHECK_ON
;
break
;
...
...
@@ -227,47 +281,62 @@ void get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
/* Not legal for the FPU */
EXCEPTION
(
EX_Invalid
);
}
address
+=
*
cpu_reg_ptr
;
}
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
|
0x133
);
}
FPU_data_address
=
offset
+
(
char
*
)
*
cpu_reg_ptr
;
return
(
void
*
)
address
;
}
void
get_address_16
(
unsigned
char
FPU_modrm
,
unsigned
long
*
fpu_eip
,
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 */
#ifndef PECULIAR_486
/* This is a reasonable place to do this */
FPU_data_selector
=
FPU_DS
;
#endif PECULIAR_486
unsigned
rm
=
FPU_modrm
&
7
;
int
address
=
0
;
/* Default used for mod == 0 */
/* 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 @@ void get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
/* 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 @@ void get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
/* 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 @@ void get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
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
;
}
drivers/FPU-emu/load_store.c
View file @
893c4d2f
...
...
@@ -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,130 +46,162 @@ static unsigned char const type_table[32] = {
_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. */
pop_ptr
=
NULL
;
/* Initialized just to stop compiler warnings. */
switch
(
type_table
[(
int
)
(
unsigned
)
type
]
)
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
}
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
)
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
)
)
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
(
&
FPU_loaded_data
,
pop
_ptr
);
reg_move
(
&
loaded_data
,
st0
_ptr
);
break
;
case
001
:
/* fild m32int */
clear_C1
();
reg_load_int32
();
reg_move
(
&
FPU_loaded_data
,
pop_ptr
);
reg_load_int32
((
long
*
)
data_address
,
st0_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
)
)
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
(
&
FPU_loaded_data
,
pop
_ptr
);
reg_move
(
&
loaded_data
,
st0
_ptr
);
break
;
case
003
:
/* fild m16int */
clear_C1
();
reg_load_int16
();
reg_move
(
&
FPU_loaded_data
,
pop_ptr
);
reg_load_int16
((
short
*
)
data_address
,
st0_ptr
);
break
;
case
010
:
/* fst m32real */
clear_C1
();
reg_store_single
(
);
reg_store_single
((
float
*
)
data_address
,
st0_ptr
);
break
;
case
011
:
/* fist m32int */
clear_C1
();
reg_store_int32
(
);
reg_store_int32
((
long
*
)
data_address
,
st0_ptr
);
break
;
case
012
:
/* fst m64real */
clear_C1
();
reg_store_double
(
);
reg_store_double
((
double
*
)
data_address
,
st0_ptr
);
break
;
case
013
:
/* fist m16int */
clear_C1
();
reg_store_int16
(
);
reg_store_int16
((
short
*
)
data_address
,
st0_ptr
);
break
;
case
014
:
/* fstp m32real */
clear_C1
();
if
(
reg_store_single
(
)
)
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
(
)
)
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
(
)
)
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
(
)
)
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
);
break
;
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
);
break
;
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
();
reg_move
(
&
FPU_loaded_data
,
pop_ptr
);
reg_load_bcd
((
char
*
)
data_address
,
st0_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
);
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
);
...
...
@@ -178,60 +210,51 @@ switch ( type )
#ifdef PECULIAR_486
control_word
|=
0x40
;
/* An 80486 appears to always set this bit */
#endif PECULIAR_486
NO_NET_DATA_EFFECT
;
NO_NET_INSTR_EFFECT
;
break
;
return
1
;
case
025
:
/* fld m80real */
clear_C1
();
reg_load_extended
();
reg_move
(
&
FPU_loaded_data
,
pop_ptr
);
reg_load_extended
((
long
double
*
)
data_address
,
st0_ptr
);
break
;
case
027
:
/* fild m64int */
clear_C1
();
reg_load_int64
();
reg_move
(
&
FPU_loaded_data
,
pop_ptr
);
reg_load_int64
((
long
long
*
)
data_address
,
st0_ptr
);
break
;
case
030
:
/* fstenv m14/28byte */
fstenv
(
addr_modes
);
NO_NET_DATA_EFFECT
;
break
;
fstenv
(
addr_modes
,
(
char
*
)
data_address
);
return
1
;
case
032
:
/* fsave */
fsave
(
addr_modes
);
NO_NET_DATA_EFFECT
;
break
;
fsave
(
addr_modes
,
(
char
*
)
data_address
);
return
1
;
case
033
:
/* fbstp m80dec */
clear_C1
();
if
(
reg_store_bcd
(
)
)
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
,
FPU_
data_address
,
2
);
put_fs_word
(
control_word
,
(
short
*
)
FPU_
data_address
);
FPU_verify_area
(
VERIFY_WRITE
,
data_address
,
2
);
put_fs_word
(
control_word
,
(
short
*
)
data_address
);
RE_ENTRANT_CHECK_ON
;
NO_NET_DATA_EFFECT
;
NO_NET_INSTR_EFFECT
;
break
;
return
1
;
case
035
:
/* fstp m80real */
clear_C1
();
if
(
reg_store_extended
(
)
)
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
,
FPU_
data_address
,
2
);
put_fs_word
(
status_word
(),(
short
*
)
FPU_
data_address
);
FPU_verify_area
(
VERIFY_WRITE
,
data_address
,
2
);
put_fs_word
(
status_word
(),(
short
*
)
data_address
);
RE_ENTRANT_CHECK_ON
;
NO_NET_DATA_EFFECT
;
NO_NET_INSTR_EFFECT
;
break
;
return
1
;
case
037
:
/* fistp m64int */
clear_C1
();
if
(
reg_store_int64
(
)
)
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
;
}
drivers/FPU-emu/poly_atan.c
View file @
893c4d2f
...
...
@@ -187,16 +187,8 @@ void poly_add_1(FPU_REG *src)
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
;
src
->
exp
=
EXP_BIAS
;
...
...
drivers/FPU-emu/reg_compare.c
View file @
893c4d2f
...
...
@@ -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 @@ int compare(FPU_REG const *b)
}
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 @@ int compare(FPU_REG const *b)
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 @@ int compare(FPU_REG const *b)
/* 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 @@ int compare(FPU_REG const *b)
}
#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 @@ int compare(FPU_REG const *b)
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 @@ int compare(FPU_REG const *b)
/* 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 @@ static int compare_st_st(int nr)
{
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 @@ static int compare_u_st_st(int nr)
{
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 @@ void fcompp()
return
;
}
if
(
!
compare_st_st
(
1
)
)
{
pop
();
FPU_st0_ptr
=
&
st
(
0
);
pop
();
}
poppop
();
}
...
...
@@ -369,10 +371,7 @@ void fucompp()
if
(
FPU_rm
==
1
)
{
if
(
!
compare_u_st_st
(
1
)
)
{
pop
();
FPU_st0_ptr
=
&
st
(
0
);
pop
();
}
poppop
();
}
else
FPU_illegal
();
...
...
drivers/FPU-emu/reg_constant.c
View file @
893c4d2f
...
...
@@ -66,7 +66,7 @@ static void fld_const(FPU_REG const *c)
return
;
}
push
();
reg_move
(
c
,
FPU_st0
_ptr
);
reg_move
(
c
,
st_new
_ptr
);
clear_C1
();
}
...
...
drivers/FPU-emu/reg_div.S
View file @
893c4d2f
...
...
@@ -25,9 +25,9 @@
_reg_div
:
pushl
%
ebp
movl
%
esp
,%
ebp
#if
def
REENTRANT_FPU
#if
ndef 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 @@ LDiv_negative_result:
xorl
%
eax
,%
eax
/*
Valid
result
*/
LDiv_exit
:
#if
def
REENTRANT_FPU
#if
ndef NON_
REENTRANT_FPU
leal
-
40
(%
ebp
),%
esp
#else
leal
-
12
(%
ebp
),%
esp
#endif REENTRANT_FPU
#endif
NON_
REENTRANT_FPU
popl
%
ebx
popl
%
edi
...
...
drivers/FPU-emu/reg_ld_str.c
View file @
893c4d2f
...
...
@@ -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 @@ int reg_load_extended(void)
/* 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 @@ int reg_load_extended(void)
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 @@ int reg_load_extended(void)
/* 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 @@ int reg_load_extended(void)
/* 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 @@ int reg_load_extended(void)
/* 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 @@ int reg_load_double(void)
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 @@ int reg_load_double(void)
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 @@ int reg_load_double(void)
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 @@ int reg_load_double(void)
/* 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 @@ int reg_load_single(void)
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 @@ int reg_load_single(void)
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 @@ int reg_load_single(void)
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 @@ void reg_load_int64(void)
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 @@ void reg_load_int32(void)
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 @@ void reg_load_int16(void)
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
;
...
...
@@ -410,47 +396,44 @@ void reg_load_bcd(void)
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 @@ int reg_store_extended(void)
/* 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 @@ int reg_store_double(void)
#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 @@ int reg_store_double(void)
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 @@ int reg_store_double(void)
}
}
}
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 @@ int reg_store_double(void)
}
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 @@ int reg_store_double(void)
else
return
0
;
}
if
(
FPU_st0_ptr
->
sign
)
if
(
st0_ptr
->
sign
)
l
[
1
]
|=
0x80000000
;
RE_ENTRANT_CHECK_OFF
;
...
...
@@ -670,18 +653,18 @@ int reg_store_double(void)
/* 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 @@ int reg_store_single(void)
#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 @@ int reg_store_single(void)
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 @@ int reg_store_single(void)
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 @@ int reg_store_single(void)
}
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 @@ int reg_store_single(void)
return
0
;
}
#endif
if
(
FPU_
st0_ptr
->
sign
)
if
(
st0_ptr
->
sign
)
templ
|=
0x80000000
;
RE_ENTRANT_CHECK_OFF
;
...
...
@@ -859,27 +842,27 @@ int reg_store_single(void)
/* 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 @@ int reg_store_int64(void)
/* 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 @@ int reg_store_int32(void)
/* 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 @@ int reg_store_int16(void)
/* 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 @@ int round_to_int(FPU_REG *r)
/*===========================================================================*/
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
));
i
p_
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
));
i
nstruction_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 @@ char *fldenv(fpu_addr_modes addr_modes)
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 @@ char *fldenv(fpu_addr_modes addr_modes)
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
,
&
regs
[
stnr
]);
tag
=
regs
[
stnr
].
tag
;
/* Derived from the
fldenv()
loaded tag word. */
reg_
load_extended
((
long
double
*
)(
s
+
i
*
10
)
,
&
regs
[
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 @@ unsigned short tag_word(void)
}
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 @@ char *fstenv(fpu_addr_modes addr_modes)
#endif PECULIAR_486
put_fs_word
(
status_word
(),
(
unsigned
short
*
)
(
d
+
2
));
put_fs_word
(
tag_word
(),
(
unsigned
short
*
)
(
d
+
4
));
put_fs_word
(
i
p_
offset
,
(
unsigned
short
*
)
(
d
+
6
));
put_fs_word
(
data_operand_
offset
,
(
unsigned
short
*
)
(
d
+
0x0a
));
if
(
addr_modes
.
vm
86
)
put_fs_word
(
i
nstruction_address
.
offset
,
(
unsigned
short
*
)
(
d
+
6
));
put_fs_word
(
operand_address
.
offset
,
(
unsigned
short
*
)
(
d
+
0x0a
));
if
(
addr_modes
.
default_mode
==
VM
86
)
{
put_fs_word
((
i
p_
offset
&
0xf0000
)
>>
4
,
put_fs_word
((
i
nstruction_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 @@ char *fstenv(fpu_addr_modes addr_modes)
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 @@ char *fstenv(fpu_addr_modes addr_modes)
}
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
;
...
...
drivers/FPU-emu/reg_round.S
View file @
893c4d2f
...
...
@@ -82,7 +82,7 @@
#define UNMASKED_UNDERFLOW $2
#if
def
REENTRANT_FPU
#if
ndef NON_
REENTRANT_FPU
/*
Make
the
code
re
-
entrant
by
putting
local
storage
on
the
stack
:
*/
#define FPU_bits_lost (%esp)
...
...
@@ -97,7 +97,7 @@ FPU_bits_lost:
.
byte
0
FPU_denormal
:
.
byte
0
#endif REENTRANT_FPU
#endif
NON_
REENTRANT_FPU
.
text
...
...
@@ -127,9 +127,9 @@ fpu_reg_round: /* Normal entry point */
fpu_reg_round_sqrt
:
/
*
Entry
point
from
wm_sqrt
.
S
*/
#if
def
REENTRANT_FPU
#if
ndef 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 @@ xL_Store_significand:
jge
L_overflow
fpu_reg_round_exit
:
#if
def
REENTRANT_FPU
#if
ndef NON_
REENTRANT_FPU
popl
%
ebx
/*
adjust
the
stack
pointer
*/
#endif REENTRANT_FPU
#endif
NON_
REENTRANT_FPU
fpu_Arith_exit
:
popl
%
ebx
...
...
drivers/FPU-emu/reg_u_div.S
View file @
893c4d2f
...
...
@@ -29,7 +29,7 @@
/*
#
define
dSIGH
(
x
)
4
(
x
)
*/
#if
def
REENTRANT_FPU
#if
ndef 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 @@ FPU_result_2:
.
long
0
FPU_ovfl_flag
:
.
byte
0
#endif REENTRANT_FPU
#endif
NON_
REENTRANT_FPU
.
text
...
...
@@ -78,9 +78,9 @@ FPU_ovfl_flag:
_reg_u_div
:
pushl
%
ebp
movl
%
esp
,%
ebp
#if
def
REENTRANT_FPU
#if
ndef NON_
REENTRANT_FPU
subl
$
28
,%
esp
#endif REENTRANT_FPU
#endif
NON_
REENTRANT_FPU
pushl
%
esi
pushl
%
edi
...
...
drivers/FPU-emu/reg_u_mul.S
View file @
893c4d2f
...
...
@@ -27,7 +27,7 @@
#if
def
REENTRANT_FPU
#if
ndef 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 @@ FPU_accum_0:
.
long
0
FPU_accum_1
:
.
long
0
#endif REENTRANT_FPU
#endif
NON_
REENTRANT_FPU
.
text
...
...
@@ -50,9 +50,9 @@ FPU_accum_1:
_reg_u_mul
:
pushl
%
ebp
movl
%
esp
,%
ebp
#if
def
REENTRANT_FPU
#if
ndef NON_
REENTRANT_FPU
subl
$
8
,%
esp
#endif REENTRANT_FPU
#endif
NON_
REENTRANT_FPU
pushl
%
esi
pushl
%
edi
...
...
drivers/FPU-emu/version.h
View file @
893c4d2f
...
...
@@ -9,5 +9,4 @@
| |
+---------------------------------------------------------------------------*/
#define FPU_VERSION "wm-FPU-emu version Beta 1.11"
#define FPU_VERSION "wm-FPU-emu version 1.12"
drivers/FPU-emu/wm_sqrt.S
View file @
893c4d2f
...
...
@@ -29,7 +29,7 @@
#include "fpu_asm.h"
#if
def
REENTRANT_FPU
#if
ndef 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 @@ FPU_fsqrt_arg_1:
.
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 @@ FPU_fsqrt_arg_0:
_wm_sqrt
:
pushl
%
ebp
movl
%
esp
,%
ebp
#if
def
REENTRANT_FPU
#if
ndef NON_
REENTRANT_FPU
subl
$
28
,%
esp
#endif REENTRANT_FPU
#endif
NON_
REENTRANT_FPU
pushl
%
esi
pushl
%
edi
pushl
%
ebx
...
...
drivers/block/README.sbpcd
View file @
893c4d2f
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
-
101
P
,
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
-
52
x
(
"old"
)
and
CR
-
56
x
(
"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
...
...
@@ -46,43 +63,47 @@ This release is part of the standard kernel and consists of
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).
4. Make the device file(s). The driver uses definitely and exclusive
the MAJOR 25, so do
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
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
/<
any_name
>
b
25
3
If
you
further
make
a
link
like
...
...
@@ -91,123 +112,120 @@ and/or
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).
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.
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.
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.
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.
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.
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!
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...
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.
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
.
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
---
drivers/block/blk.h
View file @
893c4d2f
...
...
@@ -82,6 +82,9 @@ extern int * blksize_size[MAX_BLKDEV];
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
);
...
...
drivers/block/ll_rw_blk.c
View file @
893c4d2f
...
...
@@ -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
...
...
drivers/block/sbpcd.c
View file @
893c4d2f
...
...
@@ -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
* <linux/string.h> 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 <linux/errno.h>
#include <linux/sched.h>
/* #undef DS */
#include <linux/timer.h>
#include <linux/fs.h>
#include <linux/kernel.h>
...
...
@@ -118,13 +135,7 @@
#include <linux/ioport.h>
#include <linux/sbpcd.h>
#include <linux/string.h>
#if SBPCD_USE_IRQ
#include <linux/signal.h>
#endif SBPCD_USE_IRQ
#include <linux/major.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/segment.h>
...
...
@@ -133,7 +144,7 @@
#define MAJOR_NR MATSUSHITA_CDROM_MAJOR
#include "blk.h"
#define VERSION "1.
5
Eberhard Moenkeberg <emoenke@gwdg.de>"
#define VERSION "1.
6
Eberhard Moenkeberg <emoenke@gwdg.de>"
#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 @@ static int autoprobe[] =
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 @@ static int sbp_data(void);
* pattern for printk selection:
*
* (1<<DBG_INF) necessary information
* (1<<DBG_
IRQ) interrupt
trace
* (1<<DBG_
BSZ) BLOCK_SIZE
trace
* (1<<DBG_REA) "read" status trace
* (1<<DBG_CHK) "media check" trace
* (1<<DBG_TIM) datarate timer test
...
...
@@ -250,6 +272,7 @@ static int sbp_data(void);
* (1<<DBG_XA) XA mode debugging
* (1<<DBG_LCK) door (un)lock info
* (1<<DBG_SQ) dump SubQ frame
* (1<<DBG_AUD) "read audio" debugging
* (1<<DBG_000) unnecessary information
*/
#if 1
...
...
@@ -261,7 +284,9 @@ static int sbpcd_debug = (1<<DBG_INF) |
(
1
<<
DBG_IOC
)
|
(
1
<<
DBG_XA
)
|
(
1
<<
DBG_LCK
)
|
(
1
<<
DBG_SQ
)
|
(
1
<<
DBG_CHK
)
|
(
1
<<
DBG_AUD
)
|
(
1
<<
DBG_BSZ
)
|
(
1
<<
DBG_IOX
);
#endif
static
int
sbpcd_ioaddr
=
CDROM_PORT
;
/* default I/O base address */
...
...
@@ -278,6 +303,7 @@ static struct cdrom_subchnl SC;
static
struct
cdrom_volctrl
volctrl
;
char
*
str_sb
=
"SoundBlaster"
;
char
*
str_lm
=
"LaserMate"
;
char
*
str_sp
=
"SPEA"
;
char
*
type
;
/*==========================================================================*/
...
...
@@ -323,6 +349,8 @@ static u_char drv_pattern[4]={ 0x80, 0x80, 0x80, 0x80 }; /* auto speed */
/* /A:... for (i=0;i<4;i++) drv_pattern[i] |= sax_a; */
/* /N:... ndrives=i-'0'; */
static
int
sbpcd_blocksizes
[
NR_SBPCD
]
=
{
0
,
};
/*==========================================================================*/
/*
* drive space begins here (needed separate for each unit)
...
...
@@ -341,6 +369,12 @@ static struct {
int
sbp_read_frames
;
/* Number of frames being read to buffer */
int
sbp_current
;
/* Frame being currently read */
u_char
mode
;
/* read_mode: READ_M1, READ_M2, READ_SC, READ_AU */
#if READ_AUDIO
u_char
*
aud_buf
;
/* Pointer to internal data buffer,
space allocated during sbpcd_init() */
#endif READ_AUDIO
u_char
drv_type
;
u_char
drv_options
;
u_char
status_byte
;
...
...
@@ -405,7 +439,7 @@ static struct {
int
in_SpinUp
;
}
DriveStruct
[
4
];
}
DriveStruct
[
NR_SBPCD
];
/*
* drive space ends here (needed separate for each unit)
...
...
@@ -739,14 +773,10 @@ static void xx_ReadStatus(void)
if
(
!
new_drive
)
OUT
(
CDo_command
,
0x81
);
else
{
#if SBPCD_DIS_IRQ
cli
();
#endif SBPCD_DIS_IRQ
SBPCD_CLI
;
OUT
(
CDo_command
,
0x05
);
for
(
i
=
0
;
i
<
6
;
i
++
)
OUT
(
CDo_command
,
0
);
#if SBPCD_DIS_IRQ
sti
();
#endif SBPCD_DIS_IRQ
SBPCD_STI
;
}
}
/*==========================================================================*/
...
...
@@ -791,21 +821,17 @@ int cmd_out(void)
for
(
i
=
0
;
i
<
7
;
i
++
)
DPRINTF
((
DBG_CMD
,
" %02X"
,
drvcmd
[
i
]));
DPRINTF
((
DBG_CMD
,
"
\n
"
));
#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
;
}
if
(
response_count
!=
0
)
{
if
(
cmd_type
!=
0
)
{
if
(
sbpro_type
)
OUT
(
CDo_sel_d_i
,
0x01
);
if
(
sbpro_type
==
1
)
OUT
(
CDo_sel_d_i
,
0x01
);
DPRINTF
((
DBG_INF
,
"SBPCD: misleaded to try ResponseData.
\n
"
));
if
(
sbpro_type
)
OUT
(
CDo_sel_d_i
,
0x00
);
if
(
sbpro_type
==
1
)
OUT
(
CDo_sel_d_i
,
0x00
);
return
(
-
22
);
}
else
i
=
ResponseInfo
();
...
...
@@ -1738,7 +1764,7 @@ static int switch_drive(int num)
d
=
num
;
i
=
num
;
if
(
sbpro_type
)
i
=
(
i
&
0x01
)
<<
1
|
(
i
&
0x02
)
>>
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 @@ static int DiskInfo(void)
{
int
i
;
#if READ_AUDIO
DriveStruct
[
d
].
mode
=
READ_M1
;
#endif READ_AUDIO
i
=
SetSpeed
();
if
(
i
<
0
)
{
...
...
@@ -2139,6 +2169,51 @@ static int xx_PlayAudioMSF(int pos_audio_start,int pos_audio_end)
}
/*==========================================================================*/
/*==========================================================================*/
/*==========================================================================*/
/*
* 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 @@ static int sbpcd_ioctl(struct inode *inode,struct file *file,
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,13 +2465,237 @@ static int sbpcd_ioctl(struct inode *inode,struct file *file,
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
));
...
...
@@ -2430,63 +2723,6 @@ static void sbp_transfer(void)
}
}
/*==========================================================================*/
/*
* 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.
*/
...
...
@@ -2513,9 +2749,8 @@ static void do_sbpcd_request(void)
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 @@ static void do_sbpcd_request(void)
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 @@ static void do_sbpcd_request(void)
}
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 @@ static void sbp_read_cmd(void)
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 @@ static int sbp_data(void)
for
(
frame
=
DriveStruct
[
d
].
sbp_current
;
frame
<
DriveStruct
[
d
].
sbp_read_frames
&&!
error_flag
;
frame
++
)
{
#if SBPCD_DIS_IRQ
cli
();
#endif SBPCD_DIS_IRQ
SBPCD_CLI
;
try
=
maxtim_data
;
#if LONG_TIMING
for
(
timeout
=
jiffies
+
900
;
;
)
...
...
@@ -2743,19 +2973,16 @@ static int sbp_data(void)
break
;
}
#if SBPCD_DIS_IRQ
sti
();
#endif SBPCD_DIS_IRQ
SBPCD_STI
;
CLEAR_TIMER
;
error_flag
=
0
;
p
=
DriveStruct
[
d
].
sbp_buf
+
frame
*
CD_FRAMESIZE
;
if
(
sbpro_type
)
OUT
(
CDo_sel_d_i
,
0x01
);
if
(
sbpro_type
==
1
)
OUT
(
CDo_sel_d_i
,
0x01
);
if
(
cmd_type
==
READ_M2
)
READ_DATA
(
CDi_data
,
xa_head_buf
,
CD_XA_HEAD
);
READ_DATA
(
CDi_data
,
p
,
CD_FRAMESIZE
);
if
(
cmd_type
==
READ_M2
)
READ_DATA
(
CDi_data
,
xa_tail_buf
,
CD_XA_TAIL
);
if
(
sbpro_type
)
OUT
(
CDo_sel_d_i
,
0x00
);
if
(
sbpro_type
==
1
)
OUT
(
CDo_sel_d_i
,
0x00
);
DriveStruct
[
d
].
sbp_current
++
;
if
(
cmd_type
==
READ_M2
)
{
...
...
@@ -2773,9 +3000,7 @@ static int sbp_data(void)
data_waits
=
data_tries
=
0
;
}
}
#if SBPCD_DIS_IRQ
sti
();
#endif SBPCD_DIS_IRQ
SBPCD_STI
;
if
(
error_flag
)
/* must have been spurious D_RDY or (ATTN&&!D_RDY) */
{
...
...
@@ -2786,9 +3011,7 @@ static int sbp_data(void)
if
(
!
new_drive
)
{
#if SBPCD_DIS_IRQ
cli
();
#endif SBPCD_DIS_IRQ
SBPCD_CLI
;
i
=
maxtim_data
;
for
(
timeout
=
jiffies
+
100
;
timeout
>
jiffies
;
timeout
--
)
{
...
...
@@ -2808,14 +3031,10 @@ static int sbp_data(void)
{
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 @@ static void sbpcd_release(struct inode * ip, struct file * file)
*/
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 @@ static struct file_operations sbpcd_fops =
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 @@ static struct sigaction sbpcd_sigaction =
* sbpcd=0x230,SoundBlaster
* or
* sbpcd=0x300,LaserMate
* or
* sbpcd=0x330,SPEA
*
* (upper/lower case sensitive here!!!).
*
...
...
@@ -2966,8 +3181,9 @@ static struct sigaction sbpcd_sigaction =
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
;
...
...
@@ -2985,6 +3201,57 @@ void sbpcd_setup(char *s, int *p)
else
CDi_data
=
sbpcd_ioaddr
+
2
;
}
/*==========================================================================*/
/*
* 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.
*/
...
...
@@ -3006,6 +3273,8 @@ u_long sbpcd_init(u_long mem_start, u_long mem_end)
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 @@ u_long sbpcd_init(u_long mem_start, u_long mem_end)
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,63 +3373,67 @@ u_long sbpcd_init(u_long mem_start, u_long mem_end)
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
(
MA
TSUSHITA_CDROM_MAJO
R
,
"sbpcd"
,
&
sbpcd_fops
)
!=
0
)
if
(
register_blkdev
(
MA
JOR_N
R
,
"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
[
MA
TSUSHITA_CDROM_MAJO
R
].
request_fn
=
DEVICE_REQUEST
;
read_ahead
[
MA
TSUSHITA_CDROM_MAJOR
]
=
4
;
/* just one frame */
blk_dev
[
MA
JOR_N
R
].
request_fn
=
DEVICE_REQUEST
;
read_ahead
[
MA
JOR_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
;
j
++
)
{
printk
(
"SBPCD: Can't get IRQ%d for sbpcd driver
\n
"
,
SBPCD_INTR_NR
);
sti
();
/* to avoid possible "printk" bug */
}
#endif SBPCD_USE_IRQ
if
(
DriveStruct
[
j
].
drv_minor
==-
1
)
continue
;
/*
* allocate memory for the frame buffers
*/
for
(
j
=
0
;
j
<
NR_SBPCD
;
j
++
)
{
if
(
DriveStruct
[
j
].
drv_minor
==-
1
)
continue
;
DriveStruct
[
j
].
sbp_buf
=
(
u_char
*
)
mem_start
;
mem_start
+=
SBP_BUFFER_FRAMES
*
CD_FRAMESIZE
;
#if READ_AUDIO
DriveStruct
[
j
].
aud_buf
=
(
u_char
*
)
mem_start
;
mem_start
+=
CD_FRAMESIZE_RAW
;
#endif READ_AUDIO
/*
* set the block size
*/
sbpcd_blocksizes
[
j
]
=
CD_FRAMESIZE
;
}
blksize_size
[
MAJOR_NR
]
=
sbpcd_blocksizes
;
DPRINTF
((
DBG_INF
,
"SBPCD: init done.
\n
"
));
sti
();
/* to avoid possible "printk" bug */
return
(
mem_start
);
}
/*==========================================================================*/
/*
* adopted from sr.c
*
* Check if the media has changed in the CD-ROM drive.
* used externally (isofs/inode.c
) - but still does not work.
*
* used externally (isofs/inode.c
, fs/buffer.c)
*
Currently disabled (has to get "synchronized").
*/
int
check_sbpcd_media_change
(
int
full_dev
,
int
unused_minor
)
{
int
st
;
if
(
MAJOR
(
full_dev
)
!=
MATSUSHITA_CDROM_MAJOR
)
DPRINTF
((
DBG_CHK
,
"SBPCD: media_check (%d) called
\n
"
,
MINOR
(
full_dev
)));
return
(
0
);
/* "busy" test necessary before we really can check */
if
((
MAJOR
(
full_dev
)
!=
MAJOR_NR
)
||
(
MINOR
(
full_dev
)
>=
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
();
DPRINTF
((
DBG_CHK
,
"SBPCD: media_check: %02X
\n
"
,
DriveStruct
[
d
].
status_byte
));
...
...
drivers/net/Space.c
View file @
893c4d2f
...
...
@@ -281,6 +281,14 @@ static struct device ppp0_dev = {
#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
=
{
...
...
drivers/net/ppp.c
View file @
893c4d2f
...
...
@@ -94,6 +94,7 @@ static char ppp_warning[] = KERN_WARNING "PPP: ALERT! not INUSE! %d\n";
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 @@ ppp_init(struct device *dev)
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 @@ ppp_dev_close(struct device *dev)
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
...
...
@@ -883,6 +911,8 @@ static void ppp_receive_buf(struct tty_struct *tty, unsigned char *cp,
ppp_print_buffer
(
"receive buffer"
,
cp
,
count
,
KERNEL_DS
);
}
ppp
->
stats
.
rbytes
+=
count
;
while
(
count
--
>
0
)
{
c
=
*
cp
++
;
...
...
@@ -1367,7 +1397,7 @@ ppp_ioctl(struct tty_struct *tty, struct file *file, unsigned int i,
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
;
...
...
drivers/scsi/buslogic.c
View file @
893c4d2f
...
...
@@ -562,7 +562,6 @@ int buslogic_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
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 @@ static int setup_mailboxes(unsigned int base, struct Scsi_Host *SHpnt)
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 @@ static int getconfig(unsigned int base, unsigned char *irq,
/* 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,12 +898,16 @@ static int buslogic_query(unsigned int base, int *trans)
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 */
...
...
@@ -1018,8 +1021,13 @@ int buslogic_detect(int hostnum)
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
;
...
...
fs/buffer.c
View file @
893c4d2f
...
...
@@ -44,6 +44,9 @@ extern int check_cdu31a_media_change(int, int);
#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
};
...
...
@@ -334,6 +337,12 @@ void check_disk_change(dev_t dev)
break
;
#endif
#if defined(CONFIG_SBPCD)
case
MATSUSHITA_CDROM_MAJOR
:
i
=
check_sbpcd_media_change
(
dev
,
0
);
break
;
#endif
default:
return
;
};
...
...
include/linux/sbpcd.h
View file @
893c4d2f
...
...
@@ -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,6 +204,16 @@
#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
...
...
@@ -400,17 +415,6 @@ Read XA Parameter:
*/
#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"
*/
...
...
@@ -463,9 +467,3 @@ typedef union _blk
BLK
;
/*==========================================================================*/
kernel/Makefile
View file @
893c4d2f
...
...
@@ -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
...
...
kernel/sched.c
View file @
893c4d2f
...
...
@@ -517,6 +517,8 @@ static void second_overflow(void)
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 */
}
/*
...
...
kernel/time.c
View file @
893c4d2f
...
...
@@ -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 <linux/config.h>
...
...
@@ -32,12 +34,36 @@
#include <linux/timex.h>
extern
struct
timeval
xtime
;
#include <linux/mktime.h>
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 @@ void time_init(void)
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
);
}
time
.
mon
--
;
xtime
.
tv_sec
=
kernel_mktime
(
&
time
);
BCD_TO_BIN
(
sec
);
BCD_TO_BIN
(
min
);
BCD_TO_BIN
(
hour
);
BCD_TO_BIN
(
day
);
BCD_TO_BIN
(
mon
);
BCD_TO_BIN
(
year
);
}
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 @@ asmlinkage int sys_adjtimex(struct timex *txc_p)
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 @@ int set_rtc_mmss(unsigned long nowtime)
/* 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
)
{
...
...
mm/memory.c
View file @
893c4d2f
...
...
@@ -46,6 +46,13 @@
#include <linux/ptrace.h>
#include <linux/mman.h>
/*
* 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 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
}
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 @@ void mem_init(unsigned long start_low_mem,
invalidate
();
if
(
wp_works_ok
<
0
)
wp_works_ok
=
0
;
#ifdef CONFIG_TEST_VERIFY_AREA
wp_works_ok
=
0
;
#endif
return
;
}
...
...
net/inet/af_inet.c
View file @
893c4d2f
...
...
@@ -1137,7 +1137,7 @@ static int inet_recvfrom(struct socket *sock, void *ubuf, int size, int noblock,
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 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case
SIOCSIFMAP
:
case
SIOCGIFMAP
:
case
SIOCDEVPRIVATE
:
case
SIOCSIFSLAVE
:
case
SIOCGIFSLAVE
:
return
(
dev_ioctl
(
cmd
,(
void
*
)
arg
));
default:
...
...
net/inet/arp.c
View file @
893c4d2f
...
...
@@ -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 <linux/types.h>
...
...
@@ -846,6 +847,13 @@ int arp_get_info(char *buffer, char **start, off_t offset, int length)
/*
* 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
;
k
<
HBUFFERLEN
-
3
&&
j
<
entry
->
hlen
;
j
++
)
{
hbuffer
[
k
++
]
=
hexbuf
[
(
entry
->
ha
[
j
]
>>
4
)
&
15
];
...
...
@@ -854,6 +862,9 @@ int arp_get_info(char *buffer, char **start, off_t offset, int length)
}
hbuffer
[
--
k
]
=
0
;
#ifdef CONFIG_AX25
}
#endif
size
=
sprintf
(
buffer
+
len
,
"%-17s0x%-10x0x%-10x%s
\n
"
,
in_ntoa
(
entry
->
ip
),
...
...
@@ -926,9 +937,6 @@ static int arp_req_set(struct arpreq *req)
*/
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
;
...
...
net/inet/dev.c
View file @
893c4d2f
...
...
@@ -1267,7 +1267,7 @@ static int dev_ifsioc(void *arg, unsigned int getset)
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 @@ static int dev_ifsioc(void *arg, unsigned int getset)
if
(
dev
->
flags
&
IFF_SLAVE
)
{
restore_flags
(
flags
);
return
-
E
INVAL
;
return
-
E
BUSY
;
}
if
(
dev
->
slave
!=
NULL
)
{
...
...
net/inet/ip.c
View file @
893c4d2f
...
...
@@ -90,6 +90,7 @@ extern int last_retran;
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 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd
* 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 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd
* 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
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment