HP 3000 Manuals

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