Switch to CM Sequence [ Switch Programming User's Guide ] MPE/iX 5.0 Documentation
Switch Programming User's Guide
Switch to CM Sequence
Examples 3-3 through 3-10 are a series of code examples, intended to
illustrate the partial recompilation migration option, using an NM--> CM
switch. In these examples, the calling routine migrates to Native Mode
while the target procedure remains in Compatibility Mode.
The partial recompilation migration option typically begins with a
program that calls procedures written in languages for which there is no
NM compiler. Example 3-3 is a Pascal/V program that calls an SPL
procedure.
Example 3-3. Pascal/V Program Calling SPL
PROGRAM EXAMPLE (input,output);
TYPE
pac26 = packed array [1..26] of char;
shortint = -32768..32767;
VAR
buffer : pac26;
count : shortint;
number : integer;
FUNCTION d2a(number : integer; VAR buffer : pac26) :
shortint;
external;
BEGIN
number := 198765432;
buffer := 'xxxxxxxxxxxxxxxxxxxxxxxxxx';
count := d2a(number, buffer);
writeln('The number is: ',number);
writeln('The buffer is: ',buffer);
writeln('The count is: ',count);
END.
{end Example 3-3}
Example 3-4 illustrates a procedure that is written in a language for
which Hewlett-Packard does not supply an NM compiler. It is the SPL
procedure called by the Pascal/V program in Example 3-3.
Example 3-4. Called SPL Procedure
$CONTROL USLINIT,SUBPROGRAM,SEGMENT=EXAMPLE
BEGIN
EQUATE BASE = 10;
DEFINE D'MINIT = -214748256D#;
EQUATE OFFSET = 48;
EQUATE PLACES = 9; << size of maxint, 32-bits >>
DOUBLE PROCEDURE D'EXP(X,Y);
VALUE X, Y;
INTEGER X, Y;
BEGIN
DOUBLE XX;
<< D'EXP carries out exponentiation on positive 16-bit >>
<< integers, yielding a 32-bit result. Negative >>
<< arguments yield 0. >>
IF (X < 0) OR (Y < 0) THEN
D'EXP := 0D
ELSE
BEGIN
XX := 1D;
WHILE (Y > 0) DO
BEGIN
XX := XX * DOUBLE(X);
Y := Y - 1;
END;
D'EXP := XX;
END;
END;
INTEGER PROCEDURE D2A(D'INT, ASCII'NUMERIC);
VALUE D'INT;
DOUBLE D'INT;
BYTE ARRAY ASCII'NUMERIC;
<< D2A stands for Double-to-Ascii. It converts a 32-bit>>
<< integer into an ASCII numeric in decimal >>
<< representation and returns a count of the digits >>
<< converted. A "-" is placed at the beginning of the >>
<< number for negative integers. The "-" sign >>
<< character counts as a digit. >>
BEGIN
DOUBLE SCALE;
INTEGER DIGIT, INDEX, J;
LOGICAL SKIP'ZEROS;
Example 3-4. Called SPL Procedure, continued
INDEX := 0; << at left edge of buffer >>
MOVE ASCII'NUMERIC(INDEX) := " ";
MOVE ASCII'NUMERIC(INDEX+1) :=
ASCII'NUMERIC(INDEX),(PLACES);
IF (D'INT = D'MININT) THEN
BEGIN
MOVE ASCII'NUMERIC := "-214748256";
INDEX := 10;
END
ELSE
BEGIN
IF (D'INT < 0D) THEN
BEGIN
D'INT := \D'INT\;
ASCII'NUMERIC(INDEX) := "-";
INDEX := INDEX + 1;
END;
SKIP'ZEROS := TRUE; << skip leading 0's >>
FOR J := (PLACES - 1) STEP -1 UNTIL 0 DO
BEGIN
SCALE := D'EXP(BASE,J);
DIGIT := INTEGER(D'INT/SCALE);
IF (DIGIT <> 0) OR (SKIP'ZEROS = FALSE)
OR (J = 0) THEN
BEGIN
SKIP'ZEROS := FALSE;
D'INT := D'INT - (DOUBLE(DIGIT) * SCALE);
ASCII'NUMERIC(INDEX) :=
BYTE(DIGIT + OFFSET);
INDEX := INDEX + 1;
END;
END;
END;
D2A := INDEX; << return how many characters in number>>
END;
END.
{end Example 3-4}
Before migration, the Segmenter was needed to combine the preceding
program and its called procedure. Example 3-5 is an illustration of such
a Segmenter session to combine the program and the procedure.
Example 3-5. Segmenter Session
:SPL EXAMPLE2,,*LP
$CONTROL USLINIT,SUBPROGRAM,SEGMENT=EXAMPLE
^
***** WARNING #001 ***** SUBPROGRAM AND USL INITIALIZED
PRIMARY DB STORAGE=%000; SECONDARY DB STORAGE=%00000
NO. ERRORS=0000; NO. WARNINGS=0001
PROCESSOR TIME=0:00:00; ELAPSED TIME=0:00:00
END OF COMPILE
:SEGMENTER
HP32050A.02.00 SEGMENTER/3000 (C) HEWLETT-PACKARD CO 1985
-SL SL
-PURGESL SEGMENT,EXAMPLE
-USL $OLDPASS
-LISTUSL
USL FILE $OLDPASS.DTJ.DTEST
EXAMPLE
D2A 143 P A C N R
D'EXP 34 P A C N R
FILE SIZE 144000( 620. 0)
DIR. USED 255( 1. 55) INFO USED 205( 1. 5)
DIR. GARB. 0( 0. 0) INFO GARB. 0( 0. 0)
DIR. AVAIL. 14123( 60.123) INFO AVAIL. 127173( 534.173)
-ADDSL EXAMPLE
-LISTSL EXAMPLE
SL FILE SL.DTJ.DTEST
SEGMENT 2 EXAMPLE LENGTH 204
ENTRY POINTS CHECK CAL STT ADR
D2A 0 C 1 0
D'EXP 0 C 2 143
EXTERNALS CHECK STT SEG
001
-EXIT
END OF SUBSYSTEM
{end Example 3-5}
The migration of routines for which NM compilers exist can be
accomplished by recompiling the routine using one of the NM optimizing
compilers. The code example in Example 3-6 is the HP Pascal/XL version
of the Pascal/V program in Example 3-3. It illustrates that migration
through recompilation may involve little or no change to source code.
Example 3-6. HP Pascal/XL Version of Pascal/V Program
$standard_level 'ext_modcal'$
$os 'MPE/XL'$
PROGRAM XAMPL36(input,output);
TYPE
pac26 = packed array [1..26] of char;
shortint = -32768..32767;
VAR
buffer : pac26;
count : shortint;
number : integer;
FUNCTION d2a(number : integer; VAR buffer : pac26) :
shortint;
external;
BEGIN
number := 198765432;
buffer := 'xxxxxxxxxxxxxxxxxxxxxxxxxx';
count := d2a(number, buffer);
writeln('The number is: ', number);
writeln('The buffer is: ', buffer);
writeln('The count is: ', count);
END.
{end Example 3-6}
However, if nothing else is done, an error results because the NM loader
cannot resolve the external procedure reference because the procedure
resides in a CM SL. Example 3-7 illustrates the link error obtained from
referencing the called SPL procedure from the HP Pascal/XL program in
Example 3-6.
Example 3-7. Link Error
:PASXLLK XAMPL36,,$null
PAGE 1 HP PASCAL/XL HP31502A.01.00 COPYRIGHT HEWLETT-PACKARD CO. 1986
SAT, NOV 21, 1987, 11:40 AM
NUMBER OF ERRORS = 0 NUMBER OF WARNINGS = 0
PROCESSOR TIME 0: 0: 1 ELAPSED TIME 0: 0: 0
NUMBER OF LINES = 25 LINES/MINUTE = 2645.5
NUMBER OF NOTES = 0
END OF COMPILE
LinkEd> link from $oldpass;to=
HP Link Editor/XL (HP30315A.01.00) Copyright Hewlett-Packard Co 1986
END OF LINK
:$oldpass
UNRESOLVED EXTERNALS: d2a (LDRERR 512)
UNABLE TO LOAD PROGRAM TO BE RUN. (CIERR 625)
There are two alternatives for resolving the external reference so that
your NM routine can access the CM SPL procedure:
* You can alter the original source code of the HP Pascal/XL routine to
include the required data setup and an in-line Switch that calls the
appropriate Switch intrinsic. Example 3-8 illustrates such an
in-line Switch.
* You can potentially avoid any changes to original source code by
writing a Switch stub to perform the actual mode switch (by setting
up parameters for and invoking the appropriate Switch intrinsic).
Example 3-9 illustrates a Switch stub.
Example 3-8. HP Pascal/XL Program With In-line Switch
$standard_level 'ext_modcal'$
$os 'MPE/XL'$
PROGRAM XAMPL38(INPUT, OUTPUT);
CONST
Pidt_Known = 0; {by number}
Pidt_Name = 1; {by name}
Pidt_Plabel = 2; {by plabel}
System_Sl = 0; {search library}
Logon_Pub_Sl = 1;
Logon_Group_Sl = 2;
Pub_Sl = 3;
Group_Sl = 4;
Method_Normal = 0; {Switch copy mode}
Method_Split = 1;
Method_No_Copy = 2;
Parm_Type_Value = 0; {value parameter}
Parm_Type_Word_Ref = 1; {reference parm, word addr}
Parm_Type_Byte_Ref = 2; {reference parm, byte addr}
Ccg = 0; {condition code greater (>)}
Ccl = 1; {condition code less (<)}
Cce = 2; {condition code equal (=)}
All_ok = 0; {used in status check}
Example 3-8. HP Pascal/XL Program With Inline Switch, continued
TYPE
BIT8 = 0..255;
BIT16 = 0..65535;
BIT8_A1 = $ALIGNMENT 1$ BIT8;
BIT16_A1 = $ALIGNMENT 1$ BIT16;
CM_PROC_NAME = PACKED ARRAY [1..16] of CHAR;
GENERIC_BUFFER = PACKED ARRAY [1..65535] of CHAR;
SHORTINT = -32768..32767;
SCM_PROCEDURE =
PACKED RECORD
CASE p_proc_id_type : BIT8 of
Pidt_Known:
(p_fill : BIT8_A1;
p_proc_id : BIT16_A1);
Pidt_Name:
(p_lib : BIT8_A1;
(p_proc_name : CM_PROC_NAME);
Pidt_Plabel:
(p_plabel : BIT16_A1);
END; {record}
SCM_IO_TYPE = SET OF (input_parm, output_parm);
PARM_DESC = PACKED RECORD
pd_parmptr : GLOBALANYPTR;
pd_parmlen : BIT16;
pd_parm_type : BIT16;
pd_io_type : SCM_IO_TYPE;
END; {record}
SCM_PARM_DESC_ARRAY = ARRAY [0..31] of PARM_DESC;
CCODE_TYPE = shortint;
xlstatus = record case integer of
0 : (all : integer);
1 : (info : shortint;
subsys : shortint);
end;
pac26 = packed array [1..26] of char;
localanyptrrec = record
rtn_addr : localanyptr; { for alignment }
end;
VAR
condcode : shortint;
count : shortint;
status : xlstatus;
parms : scm_parm_desc_array;
proc_info : scm_procedure;
i : integer;
Example 3-8. HP Pascal/XL Program With Inline Switch, continued
VAR
method : integer;
buffer : pac26;
nparms : integer;
rtn_len : integer;
rtn_val : localanyptrrec; {localanyptr}
procedure HPSWITCHTOCM; intrinsic;
BEGIN
proc_info.p_lib := group_sl;
proc_info.p_proc_name := 'D2A '; {procedure name}
method := method_normal; {single stack}
nparms := 2;
i := 123456789; {value to convert}
parms[1].pd_parmptr := addr(i);
parms[1].pd_parmlen := 4; {bytes}
parms[1].pd_parm_type := parm_type_value;
parms[1].pd_io_type :=
parms[1].pd_io_type + [input_parm];
buffer := ";
parms[2].pd_parmptr := addr(buffer);
parms[2].pd_parmlen := 6; {bytes}
parms[2].pd_parm_type := parm_type_byte_ref;
parms[2].pd_io_type :=
parms[2].pd_io_type + [output_parm];
rtn_len := 2; {bytes}
rtn_val.rtn_addr := addr(count);
condcode := 2; {CCE}
status.all := 0;
writeln('The number to convert = ',i);
writeln('The buffer contents are: ',buffer);
HPSWITCHTOCM(proc_info, method, nparms, parms,
rtn_len, rtn_val, condcode, status);
writeln('Switch status : subsys ',status.subsys);
writeln(' : info ',status.info);
writeln('Count of converted digits (+sign) = ',count);
writeln('The buffer contents are: ',buffer);
END. {end Example 3-8}
NOTE The status parameter returns information concerning the success of
the intrinsic's execution. It is considered good programming
practice to check the value of status after making an intrinsic
call. Normally this would involve a conditional statement, with
the value of status determining the execution path. In Example
3-8, this sort of test is intentionally omitted. Instead, the
routine prints out the values of the status parameter fields.
Example 3-9. HP Pascal/XL Switch Stub
$subprogram$
$check_actual_parm 0$
$check_formal_parm 0$
$standard_level 'ext_modcal'$
$os 'MPE/XL'$
$tables off$
$code_offsets off$
$xref off$
$type_coercion 'representation'$
PROGRAM XAMPL39(INPUT, OUTPUT);
CONST
Pidt_Known = 0; {by number}
Pidt_Name = 1; {by name}
Pidt_Plabel = 2; {by plabel}
System_Sl = 0; {search library}
Logon_Pub_Sl = 1;
Logon_Group_Sl = 2;
Pub_Sl = 3;
Group_Sl = 4;
Method_Normal = 0; {Switch copy mode}
Method_Split = 1;
Method_No_Copy = 2;
Parm_Type_Value = 0; {value parameter}
Parm_Type_Word_Ref = 1; {reference parm, word addr}
Parm_Type_Byte_Ref = 2; {reference parm, byte addr}
Ccg = 0; {condition code greater (>)}
Ccl = 1; {condition code less (<)}
Cce = 2; {condition code equal (=)}
All_ok = 0; {used in status check}
Example 3-9. HP Pascal/XL Switch Stub, continued
TYPE
BIT8 = 0..255;
BIT16 = 0..65535;
BIT8_A1 = $ALIGNMENT 1$ BIT8;
BIT16_A1 = $ALIGNMENT 1$ BIT16;
CM_PROC_NAME = PACKED ARRAY [1..16] of CHAR;
GENERIC_BUFFER = PACKED ARRAY [1..65535] of CHAR;
SCM_PROCEDURE =
PACKED RECORD
CASE p_proc_id_type : BIT8 of
Pidt_Known:
(p_fill : BIT8_A1;
p_proc_id : BIT16_A1);
Pidt_Name:
(p_lib : BIT8_A1;
(p_proc_name : CM_PROC_NAME);
Pidt_Plabel:
(p_plabel : BIT16_A1);
END; {record}
SCM_IO_TYPE = SET OF (input_parm, output_parm);
PARM_DESC = PACKED RECORD
pd_parmptr : GLOBALANYPTR;
pd_parmlen : BIT16;
pd_parm_type : BIT16;
pd_io_type : SCM_IO_TYPE;
END; {record}
SCM_PARM_DESC_ARRAY = ARRAY [0..31] of PARM_DESC;
CCODE_TYPE = shortint;
xlstatus = record case integer of
0 : (all : integer);
1 : (info : shortint;
subsys : shortint);
end;
{Declare all types which can be passed to this stub }
{so that 16-bit alignments are allowed. }
hp_shortint = $alignment 2$ shortint;
hp_integer = $alignment 2$ integer;
hp_real = $alignment 2$ real;
hp_long = $alignment 2$ longreal;
hp_char = $alignment 1$ char;
Example 3-9. HP Pascal/XL Switch Stub, continued
procedure HPSWITCHTOCM; intrinsic;
procedure HPSETCCODE; intrinsic;
procedure QUIT; intrinsic;
{End of OUTER BLOCK GLOBAL declarations }
FUNCTION D2A $ALIAS 'D2A'$
(
NUMBER : INTEGER;
ANYVAR BUFFER : GENERIC_BUFFER
) : SHORTINT
OPTION UNCHECKABLE_ANYVAR;
VAR
proc_info : scm_procedure;
parms : scm_parm_desc_array;
method : integer;
nparms : integer;
funclen : integer;
funcptr : integer;
byte_len_of_parm : bit16;
condcode : shortint;
status : xlstatus;
VAR retval : shortint;
VAR loc_number : integer;
BEGIN {STUB procedure D2A}
{Initialization}
{Set up procedure information--name, lib, etc.}
proc_info.p_proc_id_type := pidt_load;
proc_info.p_lib := group_sl;
proc_info.p_proc_name := 'D2A '; {procedure name}
{Set up miscellaneous variables}
method := method_normal; {single stack}
nparms := 2;
{Set up length/pointers for functional return if this}
{is a FUNCTION. Set length to zero, pointer to NIL }
{if this is not a FUNCTION. }
funclen := SIZEOF(retval);
funcptr := INTEGER(LOCALANYPTR(ADDR(retval)));
Example 3-9. HP Pascal/XL Switch Stub, continued
{Make a local copy of all VALUE parameters}
loc_number := NUMBER;
{Build the parm descriptor array to describe each}
{parameter. }
{NUMBER -- Input only by VALUE}
byte_len_of_parm := 4;
parms[0].pd_parmptr := addr(loc_number);
parms[0].pd_parmlen := byte_len_of_parm;
parms[0].pd_parm_type := parm_type_value;
parms[0].pd_io_type := [input_parm];
{BUFFER -- Output only by REFERENCE}
byte_len_of_parm := 6;
parms[1].pd_parmptr = addr(buffer);
parms[1].pd_parmlen = byte_len_of_parm;
parms[1].pd_parm_type := parm_type_byte_ref;
parms[1].pd_io_type := [output_parm];
{Do Switch call}
HPSWITCHTOCM(proc_info, method, nparms, parms,
funclen, funcptr, condcode, status);
if (status.all <> all_ok) then
begin {Switch subsystem error}
QUIT (status.info); {handles error codes}
end; {Switch subsystem error}
HPSETCCODE (condcode);
D2A := retval;
END; {stub procedure D2A}
begin {main}
end. {main}
{end Example 3-9}
On MPE XL, a LinkEdit session is used to combine a routine and its
external references. Example 3-10 represents a LinkEdit session to
combine the compiled stub procedure of Example 3-9 with the compiled HP
Pascal/XL program of Example 3-6.
When the LinkEdit session is completed, the partial recompilation
migration is complete. The error of Example 3-7 will no longer occur,
and you can run the HP Pascal/XL routine, still accessing the CM SPL
procedure.
Before beginning the LinkEdit session, you need to compile both the
source for the program in Example 3-6 and the Switch stub source code in
Example 3-9. Since both routines are written in Pascal, use the PASXL
command to invoke the HP Pascal/XL compiler and create NM object modules.
The following command compiles the main program (Example 3-6) and yields
an object code file named APPOBJ:
PASXL XAMPL36, APPOBJ
The next command compiles the Switch stub (Example 3-9) and yields an
object code file named STUBOBJ:
PASXL XAMPL39, STUBOBJ
For more information about the PASXL command or the commands to invoke
other NM compilers, refer to the MPE XL Commands Reference Manual
(32650-90003).
Example 3-10. LinkEdit Session
{The first LinkEdit session illustrates how to
create or designate an NM Executable Library (XL)
and add a Switch stub object module to it. This
example also shows how to create an executable
NM program that accesses the XL. If you want to
make the Switch stub object module accessible to
more than one application, this is the appropriate
course to follow. }
:LINKEDIT
{If the XL to which the stub object code is to be
added does not exist, create it and add the object
module to it as follows. }
LinkEd> BUILDXL MYXL
LinkEd> ADDXL FROM=STUBOBJ
{If the XL to which the stub object code is to be
added already exists, designate it and add the
object module to it as follows. }
LinkEd> XL XL=MYXL
LinkEd> ADDXL FROM=STUBOBJ
{Finally, to create an executable program (MYPROG),
use the LINK command as follows: }
LinkEd> LINK FROM=APPOBJ; TO=MYPROG; XL=MYXL
{The second LinkEdit session illustrates how to
link a Switch stub object module into an NM program
file. If you do not want to make the object code
available for shared use, this is the appropriate
choice. }
:LINKEDIT
LinkEd> LINK FROM=APPOBJ, STUBOBJ; TO=MYPROG
{You can also issue the LINK command directly at
the Command Interpreter prompt (:), as follows: }
:LINK FROM=APPOBJ, STUBOBJ; TO=MYPROG
For more information about the Link Editor, refer to the Link Editor/XL
Reference Manual (32650-90030).
MPE/iX 5.0 Documentation