Traps [ HP Pascal/iX Programmer's Guide ] MPE/iX 5.0 Documentation
HP Pascal/iX Programmer's Guide
Traps
Your HP Pascal program can use these MPE/iX traps:
* MPE/iX intrinsic XLIBTRAP, which traps library errors.
* MPE/iX intrinsic XARITRAP (the MPE/iX version of the MPE intrinsic
XARITRAP), which traps arithmetic errors.
* MPE/iX intrinsics ARITRAP and HPENBLTRAP, which allow you to
enable and disable trap conditions.
* MPE intrinsic XCONTRAP, which specifies a user-defined routine to
handle the subsystem break (CONTROL Y).
The subsections of this section explain how to use these traps.
NOTE The user trap-handling routines whose addresses are passed to the
traps in this section must be level-one routines.
ARITRAP and HPENBLTRAP Intrinsics
The MPE/iX intrinsics ARITRAP and HPENBLTRAP are supported by the Trap
Subsystem. ARITRAP allows a user program to enable or disable traps
collectively. HPENBLTRAP is a new MPE/iX intrinsic that allows a user
program to enable selected trap conditions.
These terms apply to trap conditions:
Term Meaning
enable To allow a trap to be raised if the trap condition occurs.
arm To specify that a particular trap handler is to be called if a
certain trap is raised (the trap must be enabled to be
raised).
disable To prevent a trap from being raised, even if the trap
condition occurs.
By default, all traps except IEEE floating-point traps are enabled.
(This complies with the IEEE floating-point standard, which stipulates
that IEEE traps are to remain disabled by default.)
Syntax
ARITRAP (flag);
HPENBLTRAP (mask, oldmask);
Parameters
flag 32-bit integer, passed by value. If flag is zero, all traps
are disabled; otherwise, all traps are enabled.
mask 32-bit integer, passed by value, whose bits specify which trap
conditions are enabled. The assignment of each position in
the bit mask is described in "XARITRAP Intrinsic."
oldmask 32-bit integer, passed by reference, in which the old value of
mask is returned.
On MPE/iX, declare ARITRAP and HPENBLTRAP as external procedures this
way:
PROCEDURE ARITRAP; INTRINSIC;
PROCEDURE HPENBLTRAP; INTRINSIC;
On HP-UX, declare ARITRAP and HPENBLTRAP as external procedures this way:
$PUSH; UPPERCASE ON$
PROCEDURE ARITRAP (Flag : integer); EXTERNAL;
PROCEDURE HPENBLTRAP ( Mask : integer;
VAR OldMask : integer
); EXTERNAL;
$POP$
Example
ARITRAP (1); {enables all traps}
HPENBLTRAP (Hex('007C0000'), OldMask); {enables IEEE floating-point traps}
XLIBTRAP Intrinsic
The MPE/iX intrinsic XLIBTRAP is supported by the HP Pascal run-time
library. It enables a user program to arm a library trap handling
procedure (Library Trap Handler). Subsequently, any Pascal library error
causes this Library Trap Handler to be called, allowing the user to
decide whether to abort or continue the program, or correct the error.
Syntax
XLIBTRAP (plabel, oldplabel);
Parameters
plabel 32-bit integer, passed by value, which is the
address of the Library Trap Handler.
oldplabel 32-bit integer, passed by reference, in which the
old value of plabel is returned.
On MPE/iX, declare XLIBTRAP as an external procedure this way:
PROCEDURE XLIBTRAP; INTRINSIC;
On HP-UX, declare XLIBTRAP as an external procedure this way:
$PUSH; UPPERCASE ON$
PROCEDURE XLIBTRAP ( PLabel : INTEGER;
VAR OldPLabel : INTEGER
); EXTERNAL;
$POP$
XLIBTRAP stores the address of the Library Trap Handler (plabel) so that
the library routines can find the routine to call if an error occurs.
The old value of PLabel is returned in the parameter OldPLabel.
The only ways to leave a trap handler is by a normal return or by an
escape. Your library trap handler cannot execute a nonlocal goto (a goto
whose destination is outside the procedure).
NOTE This routine is available on the MPE/iX and HP-UX operating
systems. On MPE/iX, it expects an MPE-style plabel; on HP-UX, it
expects plabel to be the actual address of the Library
Trap Handler. To make your program portable, use baddress
(Library_Trap_Handler_name) as plabel.
NOTE The result record will be different if the trap has been raised
outside of the Pascal run time library.
The user's trap handler must be declared this way:
TYPE
PStkMrk = RECORD {Stack Marker}
users_PCS : integer; {space id of users code space}
users_PCO : integer; {program counter offset within the
code space}
users_SP : integer; {stack pointer of the user's
routine that called the library
routine where the error occurred}
users_DP : integer; {data pointer for the above routine}
{future implementations may have further fields to return
more information to the user's trap handler. If so, they
will not affect existing code that uses the above fields.}
END;
PROCEDURE My_Library_Trap_Handler (VAR StkRec : PStkMrk;
VAR ErrorCode : Integer;
VAR AbortFlag : Integer
);
BEGIN {My_Library_Trap_Handler}
.
.
.
END; {My_Library_Trap_Handler}
Where
StkRec A structure, as described above, passed by reference. Any
changes to the fields of this structure are not reflected in
the actual contents of the machine registers, when and if the
program resumes normal execution.
ErrorCode 32-bit integer, passed by reference, which contains the error
code. For a complete list of error codes generated by the
Pascal run-time library, see the file PASESC.PUB.SYS (on
MPE/iX) or /usr/include/pasesc.ph (on HP-UX). Either of these
files can be directly included in a user program.
AbortFlag 32-bit integer, passed by reference. If AbortFlag is zero
when the Library Trap Handler is exited, the program continues
to execute. If AbortFlag is not zero, the Pascal run-time
library prints an error message and aborts the program.
To trap all run-time library errors and have them invoke your Library
Trap Handler, call XLIBTRAP this way:
XLIBTRAP (baddress(My_Library_Trap_Handler), OldPLabel);
To disable your Library Trap Handler, pass zero to XLIBTRAP as the first
parameter.
Example
{the user declares the following Pascal record for the PStkMrk record}
TYPE
PStkMrk = RECORD {"Stack Marker"}
users_PCS,
users_PCO,
users_SP,
users_DP : integer;
END;
$INCLUDE '/usr/include/pasesc.ph'$ {this file lists all the Pascal
run-time library error codes
for the HP-UX operating system}
PROCEDURE My_Library_Trap_Handler (VAR StkRec : PStkMrk;
VAR ErrorCode : Integer;
VAR AbortFlag : Integer
);
BEGIN {My_Library_Trap_Handler}
{ignore file close errors, abort on all others}
IF (ErrorCode = PasErr_CloseError) THEN BEGIN
writeln ('Oops! File close error, continue execution');
AbortFlag := 0; {no abort}
END
ELSE
AbortFlag := 1; {print message and abort}
END; {My_Library_Trap_Handler}
XARITRAP Intrinsic
The MPE/iX intrinsic XARITRAP is supported by the Trap Subsystem.
XARITRAP enables your program to arm an arithmetic trap handling
procedure (Arithmetic Trap Handler). Subsequently, any arithmetic error
causes this Arithmetic Trap Handler to be called, allowing the user to
decide whether to abort or continue the program, or correct the error.
For more information on trap handling, see the Trap Handling Programmer's
Guide.
Syntax
To arm your Arithmetic Trap Handler, call XARITRAP this way:
XARITRAP (mask, plabel, oldmask, oldplabel);
Parameters
mask 32-bit integer by value, whose bits specify which trap
condition gets armed. The assignment of each position in
the bit mask is as follows:
Bit Error Trap
31 Compatibility Mode floating-point divide by zero
30 Integer divide by zero
29 Compatibility Mode floating-point underflow
28 Compatibility Mode floating-point overflow
27 Integer Overflow
26 Compatibility Mode double precision overflow
25 Compatibility Mode double precision underflow
24 Compatibility Mode double precision divide by zero
23 Decimal Overflow (COBOL)
22 Invalid ASCII digit (COBOL)
21 Invalid decimal digit (COBOL)
20-19 Reserved
18 Decimal divide by zero
17 IEEE floating-point inexact result
16 IEEE floating-point underflow
15 IEEE floating-point overflow
14 IEEE floating-point divide by zero
13 IEEE floating-point invalid operation
12 Range error (subrange violations, etc)
11 NIL pointer dereference
10 Result of pointer arithmetic is misaligned or error
in conversion from long to short pointer
9 Unimplemented condition traps
8 Paragraph stack overflow (COBOL)
7-1 Reserved
0 Assertion Trap
plabel 32-bit integer, passed by value, which is the address of
the Arithmetic Trap Handler.
oldmask 32-bit integer, passed by reference, in which the old value
of mask is returned.
old plabel 32-bit integer, passed by reference, in which the old value
of plabel is returned.
On MPE/iX, declare XARITRAP as an external procedure this way:
PROCEDURE XARITRAP; INTRINSIC;
On HP-UX, declare XARITRAP as an external procedure this way:
$PUSH; UPPERCASE ON$
PROCEDURE XARITRAP ( Mask,
plabel : integer;
VAR OldMask,
OldPlabel : integer
); EXTERNAL;
$POP$
XARITRAP stores the address of the Arithmetic Trap Handler (plabel) so
that the system trap handler can find the routine to call if an error
occurs. The old value of plabel is returned in the parameter OldPLabel.
The only ways to leave a trap handler is by a normal return or by an
escape. Your library trap handler cannot execute a nonlocal goto (a goto
whose destination is outside the procedure).
NOTE This routine is available on both the MPE/iX and HP-UX operating
systems. On MPE/iX, it expects an MPE-style plabel; on
HP-UX, it expects plabel to be the actual address of your
Library Trap Handler. To make your program portable, use
baddress(Arithmetic_Trap_Handler_name) as plabel.
IEEE floating-point numbers are the default (native) real numbers
in HP Precision Architecture. Compatibility Mode floating-point
numbers have the format of reals on the MPE V system. The compiler
options HP3000_32 and HP3000_16 specify native and compatibility
Mode real numbers, respectively. For more information on HP3000_32
and HP3000_16, see the HP Pascal/iX Reference Manual or the HP
Pascal/HP-UX Reference Manual, depending on your implementation.
The user's trap handler must be declared this way:
TYPE
TrapInfo= RECORD
Instruction : integer; {the actual instruction word that
caused the arithmetic trap}
PC_Offset : integer; {offset of the above instruction
within the user's code space}
PC_Space : integer; {space id of user's code space}
Error_Code : integer; {Trap type. This word is formed
by setting the bit corresponding
to the trap condition in a 32-bit
integer, with all other bits zero.
More than 1 bit will be turned on
if multiple traps occur together}
{more fields are returned for certain of the trap conditions.
See below for details}
END;
PROCEDURE My_Arith_Trap_Handler (VAR Info : TrapInfo );
BEGIN {My_Arith_Trap_Handler}
.
.
.
END; {My_Arith_Trap_Handler}
To enable (for example) all integer and IEEE floating-point traps, as
well as all pointer traps, call XARITRAP this way:
XARITRAP (
{bit 0 1 2 3 }
{ 01234567890123456789012345678901}
Binary ('00000000001111111000000000010010'),
BAddress (My_Arith_Trap_Handler),
OldMask,
OldPLabel
);
NOTE In the preceding example, the IEEE inexact result trap is not
enabled.
HP Precision Architecture has only three distinct hardware
arithmetic trap conditions: condition, [integer] overflow, and
assist exception (IEEE floating-point traps are in the last
category). The system is able to categorize most integer and
decimal traps (except integer overflow) because each category has
its own unique trapping instructions. If a condition trap occurs,
and the system cannot categorize it, unimplemented condition trap
(bit 9) is raised.
The IEEE inexact result trap (bit 17), a trap required by the IEEE
floating-point standard, indicates that a floating-point operation
may have caused an inexact result (for example, the result of
10.0/3.0 is 3.333... regardless of the number of bits of precision
you use). This trap is useful only for specialty number-crunching
programs. Indiscriminate arming of this trap can severely degrade
program performance, because almost any floating-point operation
you perform will cause this trap to be raised.
To disable your Arithmetic Trap Handler, pass zero to XARITRAP as the
second parameter.
For the following traps, the system trap handler passes your Arithmetic
Trap Handler more fields than the four defined above in the TrapInfo
record, and you must adjust TrapInfo accordingly.
Integer overflow trap
Decimal overflow trap
Invalid ASCII digit trap
Invalid decimal digit trap
IEEE floating-point traps
Compatibility Mode floating-point traps
The following sections describe the extra parameters.
Integer Overflow Trap.
The TrapInfo record must have one extra field, SubCode. SubCode (word
#5) contains one of the following codes, which tells what kind of integer
overflow occurred.
SubCode Type of Overflow
Value
1 32/64-bit overflow
2 16-bit overflow
3 8-bit overflow
4 overflow on conversion from a compatibility-mode
floating-point number
5 overflow on conversion from an IEEE floating-point number
Decimal Overflow Trap.
The TrapInfo record must have one extra field, SubCode.
SubCode (word #5) contains one of the following codes, which tells what
kind of decimal overflow occurred.
Subcode Type of Overflow
Value
1 overflow in decimal arithmetic operation
2 overflow in conversion from ASCII to decimal
Invalid ASCII Digit and Invalid Decimal Digit.
The TrapInfo record has three extra fields:
1. Subcode (word #5) contains a code 0..3. Refer to the Trap
Handling Programmer's Guide for more information.
2. Address (word #6) contains the address of the first digit of the
number
3. Count (word #7) contains the digit count
IEEE Floating Point Traps.
The TrapInfo record has six extra fields:
1. Status (word #5) contains the value in the status register of the
IEEE floating-point coprocessor. Any change in this field is
reflected in the value of the status register when the program
resumes execution.
2. Operation (word #6) contains one of the following codes, which
tells the type of floating-point operation that caused the trap.
Value Type of Operation
3 ABS
4 SQRT
5 RND
8 CNVFF
9 CNVXF
10 CNVFX
16 CMP
24 ADD
25 SUB
26 MPY
27 DIV
28 REM
3. Format (word #7) contains the type of the operands (single,
double, or quadruple). If the operation was CONVERT (CNVxx), then
the following values are returned:
Value Types of Operands
1 Source is single, result is double
3 Source is single, result is quadruple
4 Source is double, result is quadruple
If the operation was NOT a CONVERT (CNVxx), then the following
values are returned:
Value Type of Operand
0 Single
1 Double
3 Quadruple
4. source_op1_ptr (word #8) contains the address of the first
operand, which can be a single-, double- or quadruple-word
floating-point number, depending on the operation and the format.
5. source_op2_ptr (word #9) contains the address of the second
operand, which can be a single-, double-, or quadruple-word
floating-point number, depending on the operation and the format.
6. result_ptr (word #10) contains the address of the result of the
operation, which can be a single-, double-, or quadruple-word
floating-point number depending on the operation and the format.
You can examine and replace the contents of the area referenced by
result_ptr, and the Trap Subsystem will ensure that the change is
reflected in the appropriate place.
Compatibility Mode Floating-Point Traps.
The TrapInfo record has one extra field, Result_ptr.
Result_ptr (word #5) contains the address of the result of the operation,
which can be a single- or double-word floating-point number, depending on
the type of trap. You can examine and replace the contents of the area
referenced by result_ptr, and the Trap Subsystem will ensure that the
change is reflected in the appropriate place.
Example
{user declares the following Pascal record for the TrapInfo record}
TYPE
real_ptr = real;
long_ptr = longreal;
TrapInfo = RECORD
{ 1} instruction,
{ 2} pc_offset,
{ 3} pc_space,
{ 4} error_code,
{ 5} status,
{ 6} operation,
{ 7} format : integer;
{ 8} source1_ptr,
{ 9} source2_ptr,
{10} result_ptr : localanyptr;
END;
CONST
IEEE_mask = hex('0007C000');
fdiv_zero = hex('00002000'); {the error code for fl. pt. div. by 0}
{trap handler routine}
PROCEDURE IEEE_trap_handler (VAR Info : TrapInfo);
VAR
long_res_ptr : long_ptr;
real_res_ptr : real_ptr;
(Example continued on next page.)
CONST
max_real = 3.402823E+38;
max_longreal = 1.797693L+308;
BEGIN {IEEE_trap_handler}
{handle only divide-by-zero, ignore others}
WITH Info DO
IF (Error_Code = fdiv_zero) THEN
BEGIN {divide by zero}
{change the value of the result}
IF (format = 0) THEN
BEGIN {real operation}
real_res_ptr := result_ptr;
real_res_ptr^ := maxreal;
END {real operation}
ELSE IF (format = 1) THEN
BEGIN {longreal operation}
long_res_ptr := result_ptr;
long_res_ptr^ := maxlongreal;
END; {longreal operation}
END; {divide by zero}
END; {IEEE_trap_handler}
{user main program}
VAR
l1, l2, l3 : longreal;
oldmask,
oldplabel : integer;
BEGIN {main program}
ARITRAP (1); {see "ARITRAP and HPENBLTRAP Intrinsics" for details}
XARITRAP (IEEE_mask, BAddress (IEEE_trap_handler), oldmask, oldplabel);
l1 := 233.0;
l2 := 0.0;
l3 := l1/l2; {oops! divide by zero!}
writeln (l3); {the trap handler should have fixed the result of the
previous operation to maxlongreal (1.79769e+308)}
END. {main program}
XCONTRAP Intrinsic
The MPE intrinsic XCONTRAP specifies a user-defined routine (Subsystem
Break Handler) that will be called when the user enters a subsystem break
(CONTROL Y) on the keyboard. When XCONTRAP is enabled and the user
enters CONTROL Y:
* Program control is transferred to the specified user-defined
routine.
* The subsystem break function is temporarily disabled to reduce the
chance of race conditions.
If normal program execution is to resume after the interrupt, the
user-defined routine must re-enable the subsystem break by calling the
intrinsic RESETCONTROL just before it ends. On MPE/iX, a normal exit
from the user-defined routine is sufficient to return control to the
point in the program where the subsystem break was trapped.
Syntax
To arm your Subsystem Break Handler, call XCONTRAP this way:
XCONTRAP (plabel, oldplabel);
Call RESETCONTROL this way:
RESETCONTROL;
Declare XCONTRAP and RESETCONTROL this way:
PROCEDURE XCONTRAP; INTRINSIC;
PROCEDURE RESETCONTROL; INTRINSIC;
Parameters
oldplabel A 32-bit integer, passed by reference, in which the old
value of plabel is returned. If the subsystem break
handler is not armed, this value is zero.
plabel A 32-bit integer, passed by value, which is the address of
your Subsystem Break Handler.
Example
The main program is a loop. Whenever the user enters CONTROL Y on the
keyboard, control transfers to the procedure control_y_handler, which
writes the current loop counter value, then re-enables the subsystem
break, and returns to the point in the loop where the interrupt occurred.
PROGRAM control_y_test (output);
VAR
count : integer;
i : integer;
oldplabel : integer;
{Intrinsic Declarations}
PROCEDURE XCONTRAP; INTRINSIC;
PROCEDURE RESETCONTROL; INTRINSIC;
{User-defined Subsystem Break Handler}
PROCEDURE control_y_handler;
BEGIN
writeln('<Control-Y>: Count = ', count:1); {write counter value}
RESETCONTROL; {re-enable subsystem break}
END;
BEGIN
{Arm the Subsystem Break Handler,
specifying control_y_handler as the user-defined routine}
XCONTRAP (BAddress (control_y_handler), oldplabel);
{Loop}
FOR i := 1 TO 30000000 DO
count := i;
END.
If you compile, link, and run the preceding program on an MPE/iX system
and press CONTROL Y several times while it is running, the program prints
the value of count each time you press CONTROL Y. For example:
CONTROL Y: Count = 121765
CONTROL Y: Count = 2731435
CONTROL Y: Count = 5789345
CONTROL Y: Count = 10135467
CONTROL Y: Count = 23618560
MPE/iX 5.0 Documentation