Contributor: GERD KORTEMEYER 
{
GERD KORTEMEYER
here are two Units For trapping float-exceptions. In your Program you
will have to add
 Uses err387
and at the beginning of your main Program say For example
begin
 exception(overflow, masked);
 exception(underflow, dumpask);
 exception(invalid, dumpexit);
 autocorrect(zerodiv, 1.0);
 exception(precision, masked);
In this way you can choose For any kind of exception in which way it is
to be handeled. After the lines above the result of a division by zero
will be '1.0', in Case of an underflow there will be a dump of the copro
and the user will be asked For the result he wants the operation to have,
in Case of an overflow the largest available number will be chosen and
so on ...
Here are the Units
 err387 and dis387
}
{ ---------------------------------------------------------- }
{ Fehlerbehandlungsroutinen fuer den Intel 80387 bzw. 486 DX }
{ Geschrieben in Turbo Pascal 6.0 }
{ von Gerd Kortemeyer, Hannover }
{ ---------------------------------------------------------- }
Unit err387;
Interface
Uses
 dis387, Dos, Crt;
Const
 invalid = 1;
 denormal = 2;
 zero_div = 4;
 overflow = 8;
 underflow = 16;
 precision = 32;
 stackfault= 64;
 con1 = 512;
 masked = 0;
 runtime = 1;
 dump = 2;
 dumpexit = 3;
 dumpask = 4;
 autocorr = 5;
Procedure exception(which, what : Word);
Procedure autocorrect(which : Word; by : Extended);
Procedure handle_off;
Procedure handle_on;
Procedure restore_masks;
Procedure clear_copro;
Function status_Word : Word;
Var
 do_again : Word;
Implementation
Const
 valid = 0;
 zero = 1;
 spec = 2;
 empty = 3;
 topmask : Word = 14336;
 topdiv = 2048;
 anyerrors : Word = 63;
 zweipot : Array [0..15] of Word =
 (1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,
 2048, 4096, 8192, 16384, 32768);
 ex_nam : Array[0..5] of String=
 ('Invalid ',
 'Denormal ',
 'Zero-Div ',
 'Overflow ',
 'Underflow ',
 'Precision ');
Var
 setmasks : Byte;
 normal : Record
 Case Boolean OF
 True : (adr : Pointer);
 False: (pro : Procedure);
 end;
 Exit_on,
 dump_on,
 ask_on,
 auto_on,
 standard : Word;
 auto_val : Array [0..5] of Extended;
Procedure Mask(which : Word);
Var
 cw : Word;
begin
 Asm
 fstcw cw
 end;
 cw := cw or which;
 setmasks := Lo(cw);
 Asm
 fldcw cw
 end;
end;
Procedure Unmask(which : Word);
Var
 cw : Word;
begin
 Asm
 fclex
 fstcw cw
 end;
 cw := cw and not (which);
 setmasks := Lo(cw);
 Asm
 fldcw cw
 end;
end;
Procedure restore_masks;
Var
 setm : Word;
 i :Integer;
begin
 setm:=setmasks;
 For i := 0 to 5 do
 if (setm and zweipot[i])  0 then
 Mask (zweipot[i])
 else
 Unmask(zweipot[i]);
end;
Procedure clear_copro;
Var
 cw : Word;
begin
 Asm
 fstcw cw
 end;
 setmasks := Lo(cw);
 Asm
 finit
 end;
end;
Function status_Word;
begin
 Asm
 fstsw @result
 end;
end;
{ Bei welcher Exception soll was passieren? }
Procedure exception;
begin
 Case what OF
 masked : Mask(which);
 runtime :
 begin
 Unmask(which);
 standard := standard or which;
 end;
 dump :
 begin
 Unmask(which);
 standard := standard and NOT(which);
 dump_on := dump_on or which;
 Exit_on := Exit_on and NOT(which);
 ask_on := ask_on and NOT(which);
 auto_on := auto_on and NOT(which);
 end;
 dumpexit :
 begin
 Unmask(which);
 standard := standard and NOT(which);
 dump_on := dump_on or which;
 Exit_on := Exit_on or which;
 ask_on := ask_on and NOT(which);
 auto_on := auto_on and NOT(which);
 end;
 dumpask :
 begin
 Unmask(which);
 standard := standard and NOT(which);
 dump_on := dump_on or which;
 Exit_on := Exit_on and NOT(which);
 ask_on := ask_on or which;
 auto_on := auto_on and NOT(which);
 end;
 end;
end;
{ zum Setzen von Auto-Korrekt-Werten }
Procedure autocorrect;
Var
 i : Integer;
begin
 Unmask(which);
 standard := standard and NOT(which);
 dump_on := dump_on and NOT(which);
 Exit_on := Exit_on and NOT(which);
 ask_on := ask_on and NOT(which);
 auto_on := auto_on or which;
 For i := 0 to 5 do
 if (which and zweipot[i])  0 then
 auto_val[i] := by;
end;
{ ------------- Die Interrupt-Routine selbst ------------- }
Procedure errorcon; Interrupt;
Var
 copro : Record
 control_Word,
 status_Word,
 tag_Word, op,
 instruction_Pointer,
 ip, operand_Pointer, : Word;
 st : Array [0..7] of Extended;
 end;
 top : Integer; { welches Register ist Stacktop? }
 masked, { welche Exceptions maskiert? }
 occured : Byte; { welche Exceptions aufgetreten? }
 opcode : Word;
 inst_seg, { Instruction-Pointer, Segment }
 inst_off, { " , Offset }
 oper_seg, { Operand-Pointer , Segment }
 oper_off: Word; { " , Offset }
 inst_point : ^Word; { zum Adressieren des Opcodes }
 oper_point : Record
 Case Integer of { zum Adressieren des Operanden }
 1 : (ex : ^Extended);
 2 : (db : ^Double);
 3 : (si : ^Single);
 4 : (co : ^Comp);
 end;
 marker: Array [0..7] of Word; { Register-Marker nach Tag-Word }
 opt_dump, { soll ausgeben werden? }
 opt_exit, { soll aufgehoert werden? }
 opt_ask, { soll Ergebnis abgefragt werden? }
 opt_auto : Boolean; { soll Ergebnis automatisch korrigiert werden? }
 i : Integer;
 mem_access: Boolean; { gibt es Speicherzugriff? }
 op_name : String; { Mnemonik des Befehls }
{ Ersetze Stacktop durch abgefragten Wert }
Procedure ask_correct;
Var
 res : Extended;
 ch : Char;
 t : String;
 code : Integer;
begin
 Asm
 fstp res
 end;
 WriteLN;
 Write('The result would be ', res, '. Change? (y/n) ' );
 Repeat
 Repeat Until KeyPressed;
 ch := ReadKey;;
 Until ch in ['Y','y','N','n'];
 Writeln;
 if ch in ['Y','y'] then
 Repeat
 Write('New value : ');
 READLN(t);
 VAL(t, res, code);
 Until code = 0;
 Asm
 fld res
 end;
end;
Function hex(w : Word) : String; { Ausgabe als HeX-Zahl }
Const
 zif : Array [0..15] of Char = ('0','1','2','3','4','5','6','7','8','9',
 'a','b','c','d','e','f');
begin
 hex := zif[w div zweipot[12]] +
 zif[(w MOD zweipot[12]) div zweipot[8]] +
 zif[(w MOD zweipot[8]) div zweipot[4]] +
 zif[w MOD zweipot[4]];
end;
Procedure choice;
Var
 ch : Char;
begin
 WriteLN;
 Write('C)ontinue, A)bort ');
 Repeat
 Repeat Until KeyPressed;
 ch:=ReadKey;;
 if ch in ['A','a'] then
 Halt(0);
 Until ch in ['C','c'];
 WriteLN;
end;
Procedure showcopro; { Ausgeben des FSAVE - Records }
Var
 i : Integer;
begin
 TextMode(LastMode);
 HighVideo;
 WriteLN('Floating point exception, last opcode: ',hex(opcode),
 ' (',op_name,')');
 NormVideo;
 WriteLN('Instruction Pointer : ',hex(inst_seg),':',hex(inst_off),
 ' (',hex(inst_point^),')');
 if mem_access then
 begin
 WriteLN('Operand Pointer : ',hex(oper_seg),':',hex(oper_off));
 WriteLN('( Extended: ',oper_point.ex^,', Double: ',oper_point.db^);
 WriteLN(' Single : ',oper_point.si^,', Comp : ',oper_point.co^,' )');
 end
 else
 begin
 WriteLN;
 WriteLN ('No memory access');
 WriteLN;
 end;
 HighVideo;
 if (occured and stackfault) = 0 then
 begin
 WriteLN('Exception ','Masked':8,'Occured':8,'Should be masked':18);
 NormVideo;
 For i:=0 to 5 do
 WriteLN(ex_nam[i], (masked and zweipot[i])  0 : 8,
 (occured and zweipot[i])  0 : 8,
 (setmasks and zweipot[i])  0 : 18);
 HighVideo;
 end
 else
 begin
 WriteLN('Invalid Operation:');
 if (copro.status_Word and con1)  0 then
 WriteLN(' -- Stack Overflow --')
 else
 WriteLN(' -- Stack Underflow --');
 WriteLN;
 end;
 WriteLN('Reg ','Value':29,'Marked':10);
 Normvideo;
 For i := 0 to 7 do
 begin
 Write('st(',i,')', copro.st[i] : 29);
 Case marker[i] OF
 valid : WriteLN('Valid' : 10);
 spec : WriteLN('Special' : 10);
 empty : WriteLN('Empty' : 10);
 zero : WriteLN('Zero' : 10);
 end;
 end;
end;
{ Ersetze Stacktop durch Auto-Korrekt-Wert }
Procedure auto_corr;
Var
 res : Extended;
 i : Integer;
begin
 Asm
 fstp res
 end;
 For i := 0 to 5 do
 if ((occured and zweipot[i])  0) and
 ((auto_on and zweipot[i])  0) then
 res := auto_val[i];
 Asm
 fld res
 end;
end;
Procedure do_it_again;
Type
 codearr = Array[0..4] of Byte;
Var
 sam : Record
 Case Boolean OF
 True : (b: ^codearr );
 False: (p: Procedure);
 end;
 op_point : Pointer;
 x : extended;
begin
 New(sam.b);
 sam.b^[0]:=Hi(opcode);
 sam.b^[1]:=Lo(opcode);
 if mem_access then
 begin
 { --- mod r/m auf ds:[di] stellen (00ttt101) --- }
 sam.b^[1] := sam.b^[1] and not (zweipot[7] + zweipot[6] + zweipot[1]);
 sam.b^[1] := sam.b^[1] or (zweipot[2] + zweipot[0]);
 end;
 sam.b^[2] := $ca; { retf 0000 }
 sam.b^[3] := 00ドル;
 sam.b^[4] := 00ドル;
 op_point := oper_point.ex;
 Asm
 push ds
 lds di, op_point
 end;
 sam.p;
 Asm
 pop ds
 end;
 Dispose(sam.b);
end;
begin
 Asm
 push ax
 xor al,al
 out 0f0h,al
 mov al,020h
 out 0a0h,al
 out 020h,al
 pop ax
 fsave copro
 end;
 { === Pruefen, ob Bearbeitung durch ERRORCON erwuenscht === }
 if (copro.status_Word and standard)  0 then
 begin
 Asm
 frstor copro
 end;
 normal.pro; { Bye, bye ... }
 end;
 { === Auswerten des FSAVE-Records ========================= }
 { --- Opcode wie im Copro gespeichert --- }
 opcode := zweipot[15] + zweipot[14] + zweipot[12] + zweipot[11] +
 (copro.ip MOD zweipot[11]);
 op_name := dis(opcode);
 mem_access := op_name='...';
 { --- Was war maskiert, was ist passiert? --- }
 masked := Lo(copro.control_Word);
 occured := Lo(copro.status_Word );
 { --- Der Instruction-Pointer --- }
 inst_seg := copro.ip and (zweipot[15] + zweipot[14] + zweipot[13] +
 zweipot[12]);
 inst_off := copro.instruction_Pointer;
 inst_point := Ptr(inst_seg,inst_off);
 { --- Der Operand-Pointer --- }
 oper_seg := copro.op and (zweipot[15] + zweipot[14] + zweipot[13] +
 zweipot[12]);
 oper_off := copro.operand_Pointer;
 oper_point.ex := Ptr(oper_seg,oper_off);
 { --- Wer ist gerade Stacktop? --- }
 top := (copro.status_Word and topmask) div topdiv;
 { --- Einlesen der Marker aus Tag-Word --- }
 For i := 0 to 7 do
 begin
 marker[(8 + i - top) MOD 8] := (copro.tag_Word and (zweipot[i * 2] +
 zweipot[i * 2 + 1])) div zweipot[i * 2];
 end;
 { --- Welche Aktionen sollen ausgefuehrt werden? --- }
 opt_dump := (copro.status_Word and dump_on)  0;
 opt_exit := (copro.status_Word and Exit_on)  0;
 opt_ask := (copro.status_Word and ask_on )  0;
 opt_auto := (copro.status_Word and auto_on)  0;
 { === Aktionen ============================================ }
 if opt_dump then
 showcopro;
 if opt_exit then
 begin
 WriteLN;
 WriteLN('Exit Program due to Programmers request');
 HALT; { Bye, bye ... }
 end;
 if opt_dump and not (opt_ask) then
 choice;
 copro.control_Word := copro.control_Word or anyerrors;
 Asm
 frstor copro
 fclex
 end;
 { --- Befehl nochmals ausfuehren --- }
 if (occured and do_again)  0 then
 do_it_again;
 { --- Noch was? --- }
 if opt_auto then
 auto_corr;
 if opt_ask then
 ask_correct;
 restore_masks;
end;
{ ------------- Ein- und Ausschalten ------------- }
Procedure handle_on;
begin
 Getintvec(75,ドル normal.adr);
 Setintvec(75,ドル @errorcon);
end;
Procedure handle_off;
begin
 Setintvec(75,ドル normal.adr);
end;
begin
 handle_on;
 dump_on :=0;
 Exit_on :=0;
 ask_on :=0;
 auto_on :=0;
 standard:=0;
 do_again:=invalid+zero_div+denormal;
 clear_copro;
end.
Unit dis387;
Interface
Function dis(opco : Word) : String;
Implementation
Function dis;
Var
 d, op : String;
 Procedure opcr(st : Word);
 Var
 t : String;
 begin
 str(st, t);
 op := ' st,st(' + t + ')';
 end;
 Procedure opc(st : Word);
 Var
 t : String;
 begin
 str(st, t);
 op := ' st(' + t + '),st';
 end;
 Procedure op1(st : Word);
 Var
 t : String;
 begin
 str(st, t);
 op := ' st(' + t + ')';
 end;
begin
 d := '...';
 op := '';
 Case Hi(opco) OF
 $d8 :
 Case Lo(opco) div 16 OF
 $c :
 if opco MOD 16>= 8 then
 begin
 d := 'fmul';
 opcr(opco MOD 16 - 8);
 end
 else
 begin
 d := 'fadd';
 opcr(opco MOD 16);
 end;
 $e :
 if opco MOD 16>= 8 then
 begin
 d := 'fsubr';
 opcr(opco MOD 16 - 8);
 end
 else
 begin
 d := 'fsub';
 opcr(opco MOD 16);
 end;
 $f :
 if opco MOD 16>= 8 then
 begin
 d := 'fdivr';
 opcr(opco MOD 16 - 8);
 end
 else
 begin
 d := 'fdiv';
 opcr(opco MOD 16);
 end;
 end;
 $d9 :
 Case Lo(opco) OF
 $d0 : d := 'fnop';
 $e0 : d := 'fchs';
 $e1 : d := 'fabs';
 $e4 : d := 'ftst';
 $e5 : d := 'fxam';
 $e8 : d := 'fld1';
 $e9 : d := 'fld2t';
 $ea : d := 'fld2e';
 $eb : d := 'fldpi';
 $ec : d := 'fldlg2';
 $ed : d := 'fldln2';
 $ee : d := 'fldz';
 $f0 : d := 'f2xm1';
 $f1 : d := 'fyl2x';
 $f2 : d := 'fptan';
 $f3 : d := 'fpatan';
 $f4 : d := 'fxtract';
 $f5 : d := 'fprem1';
 $f6 : d := 'fdecstp';
 $f7 : d := 'fincstp';
 $f8 : d := 'fprem';
 $f9 : d := 'fyl2xp1';
 $fa : d := 'fsqrt';
 $fb : d := 'fsincos';
 $fc : d := 'frndint';
 $fd : d := 'fscale';
 $fe : d := 'fsin';
 $ff : d := 'fcos';
 end;
 $db :
 Case Lo(opco) OF
 $e2 : d := 'fclex';
 $e3 : d := 'finit';
 end;
 $dc :
 Case Lo(opco) div 16 OF
 $c :
 if opco MOD 16>= 8 then
 begin
 d := 'fmul';
 opc(opco MOD 16-8);
 end
 else
 begin
 d := 'fadd';
 opc(opco MOD 16);
 end;
 $e : if opco MOD 16>= 8 then
 begin
 d := 'fsub';
 opc(opco MOD 16 - 8);
 end
 else
 begin
 d := 'fsubr';
 opc(opco MOD 16);
 end;
 $f :
 if opco MOD 16>= 8 then
 begin
 d := 'fdiv';
 opc(opco MOD 16 - 8);
 end
 else
 begin
 d := 'fdivr';
 opc(opco MOD 16);
 end;
 end;
 $dd :
 Case Lo(opco) div 16 OF
 $c :
 begin
 d := 'ffree';
 op1(opco MOD 16);
 end;
 $d :
 if opco MOD 16>= 8 then
 begin
 d := 'fstp';
 op1(opco MOD 16 - 8);
 end
 else
 begin
 d := 'fst';
 op1(opco MOD 16);
 end;
 $e :
 if opco MOD 16>= 8 then
 begin
 d := 'fucomp';
 op1(opco MOD 16 - 8);
 end
 else
 begin
 d := 'fucom';
 op1(opco MOD 16);
 end;
 end;
 $de :
 Case Lo(opco) div 16 OF
 $c :
 if opco MOD 16>= 8 then
 begin
 d := 'fmulp';
 opc(opco MOD 16 - 8);
 end
 else
 begin
 d := 'faddp';
 opc(opco MOD 16);
 end;
 $d : d := 'fcompp';
 $e :
 if opco MOD 16>= 8 then
 begin
 d := 'fsubp';
 opc(opco MOD 16 - 8);
 end
 else
 begin
 d := 'fsubrp';
 opc(opco MOD 16);
 end;
 $f :
 if opco MOD 16>= 8 then
 begin
 d := 'fdivp';
 opc(opco MOD 16 - 8);
 end
 else
 begin
 d := 'fdivrp';
 opc(opco MOD 16);
 end;
 end;
 end;
 dis := d + op;
end;
begin
end.
 

AltStyle によって変換されたページ (->オリジナル) /