[Download
the source file]
Program mathrt_t(output);
{
Tests Pascal runtime library built-in functions:
Abs(), integer Sqr(), integer ** operator, Round(), Trunc().
All tests should pass, and error recovery tests at end should pass
when program linked with mathruntime_tune object code.
}
{$SETC M68K := UNDEFINED MWERKS | MAC68K}
{$IFC NOT M68K}
Uses
MachineExceptions; { InstallExceptionHandler }
{$ENDC}
{ Test MW Pascal MathRuntime library or its equivalent }
Type
HandlerPtr = ^Char;
error_vectors = (divide0, chk, overflow); { In 68K order, '020 p. 8-3 }
Var
i: Integer;
g_test_count : 0..MaxLongInt;
g_exception_count : Integer;
vector_p: array[error_vectors] of ^HandlerPtr;
g_save_vector: array[error_vectors] of HandlerPtr;
g_err_hdlr_68k : array[1..5] of Integer;
{$IFC NOT M68K}
g_old_hdlr_ppc : ExceptionHandler;
{$ENDC}
Procedure Check(val, expected: Longint);
begin
g_test_count := g_test_count + 1;
if val <> expected then
WriteLn(output, '###', g_test_count:4, ' ', val:0, ' # ',expected:0);
end;
Procedure Ignore(val: LongInt);
begin
end;
{ Prevent front-end evaluation of builtin functions w/ const. args. }
Function Trunc_(x: Extended): Longint;
begin
Trunc_ := Trunc(x)
end;
Function Round_(x: Extended): Longint;
begin
Round_ := Round(x)
end;
Function Abs_(x: Longint): Longint;
begin
Abs_ := Abs(x)
end;
Function Sqr_(x: Longint): Longint;
begin
Sqr_ := Sqr(x)
end;
Function Pow_(base,expon: Longint): Longint;
begin
Pow_ := base**expon
end;
{$IFC NOT M68K}
{$PUSH}
{ Can't allow runtime tests within error handler!! }
{$OV-}
{$R-}
Function MyExceptionHandler(var theException: ExceptionInformationPowerPC):
OSStatus;
begin
MyExceptionHandler := -1; { What's the best default return value? }
if theException.theKind = kTrapException then
begin
g_exception_count := g_exception_count + 1;
{ Make sure we resume after the tw instr. }
{ This add assumes only 32 bit PC! }
theException.machineState^.PC.lo := theException.machineState^.PC.lo + 4;
MyExceptionHandler := noErr;
end
end; { MyExceptionHandler }
{$POP}
{$ENDC}
Procedure Install_Err_Handler;
Var
er: error_vectors;
exception_count_addr: LongInt;
begin
{$IFC M68K}
exception_count_addr := ord(@g_exception_count);
{ Kludge: store 2-instruction (5 word) trap handler in an array }
{ Avoiding inline asm makes compatible with Apple Pascal }
g_err_hdlr_68k[1] := $0679; { ADDI.W }
g_err_hdlr_68k[2] := 1;
g_err_hdlr_68k[3] := HiWrd(exception_count_addr); { (exception_count_addr).L }
g_err_hdlr_68k[4] := LoWrd(exception_count_addr);
g_err_hdlr_68k[5] := $4E73; { RTE }
for er := divide0 to overflow do
begin
vector_p[er] := Pointer(ord(er)*4 + $14);
g_save_vector[er] := vector_p[er]^;
{ All errors share same handler }
vector_p[er]^ := @g_err_hdlr_68k;
end;
{$ELSEC}
g_old_hdlr_ppc := InstallExceptionHandler(@MyExceptionHandler);
{$ENDC}
end; { Install_Err_Handler }
Procedure Remove_Err_Handler;
Var
er: error_vectors;
begin
{$IFC M68K}
{ Restore original vectors }
for er := divide0 to overflow do
vector_p[er]^ := g_save_vector[er];
{$ELSEC}
if InstallExceptionHandler(g_old_hdlr_ppc) = nil then; { Discard result }
{$ENDC}
end; { Remove_Err_Handler }
Begin { main }
g_test_count := 0;
g_exception_count := 0;
Install_Err_Handler;
Check(Sqr_(-32767), 1073676289);
Check(Sqr_(32768), $40000000);
Check(Sqr_(46340), 2147395600);
Check(Sqr_(0), 0);
Check(Pow_(3,15), 14348907);
Check(Pow_(-3,15),-14348907);
Check(Pow_(2,30), $40000000);
Check(Pow_(-2,30), $40000000);
Check(Pow_(-2,31), -MaxLongInt-1);
Check(Pow_(10,6), 1000000);
Check(Pow_(1,-1), 1);
Check(Pow_(2,-1), 0);
Check(Pow_(2,0), 1);
Check(Pow_(-3,0), 1);
Check(Pow_(0,0), 1);
Check(Pow_(0,1), 0);
Check(Pow_(0,65536), 0);
Check(Pow_(-1,-1), -1);
Check(Pow_(-2,-1), 0);
Check(Pow_(MaxLongInt,-1), 0);
Check(Pow_(-MaxLongInt,-1), 0);
for i := 0 to +10000 do
begin
Check(Trunc(i), i);
Check(Trunc(i+0.1), i);
Check(Trunc(i+0.5), i);
Check(Trunc(i+0.99), i);
Check(Trunc(-i), -i);
Check(Trunc(-i-0.1), -i);
Check(Trunc(-i-0.5), -i);
Check(Trunc(-i-0.99), -i);
end;
Check(Trunc_(2147483646.9), 2147483646);
Check(Trunc_(-2147483646.9), -2147483646);
Check(Trunc_(-2147483648.9), -MaxLongInt-1);
for i := 0 to +10000 do
begin
Check(Round(i), i);
Check(Round(i+0.1), i);
Check(Round(i+0.49), i);
Check(Round(i+0.50), i+1);
Check(Round(i+0.99), i+1);
Check(Round(-i), -i);
Check(Round(-i-0.1), -i);
Check(Round(-i-0.49), -i);
Check(Round(-i-0.50), -i-1);
Check(Round(-i-0.99), -i-1);
end;
Check(Round_(2147483646.9), 2147483647);
Check(Round_(-2147483646.9), -2147483647);
Check(Abs_(-2983843), 2983843);
Check(Abs_(2983843), 2983843);
Check(Abs_(0), 0);
{ Test runtime errors in patched version of MathRuntime }
{ Relies upon trap handler to recover from errors }
Ignore(Pow_(0,-1));
Ignore(Pow_(2,31));
Ignore(Pow_(2,32));
Ignore(Pow_(3,20));
Ignore(Pow_(3,-20));
Ignore(Round_(-Inf));
Ignore(Trunc_(Inf));
Ignore(Trunc_(999999999999.0));
Ignore(Round_(-999999999999.0));
Ignore(Abs_(-MaxLongInt-1)); { PPC inline abs() doesn't check OV. }
if g_exception_count < 10 then
begin
Writeln(output, '### Too few traps occurred (',g_exception_count:0,')!');
end;
Remove_Err_Handler;
Writeln(output, '### Complete.')
end.
[Download the source file]