HP 3000 Manuals

Examples: NM to CM and Return [ Switch Programming User's Guide ] MPE/iX 5.0 Documentation


Switch Programming User's Guide

Examples:  NM to CM and Return 

Now consider an example of the NM--> CM mixed-mode switching process.
Suppose there is an SPL procedure CONVERTDATE that resides in a CM SL and
that you want to access from MPE XL code.  CONVERTDATE converts an input
parameter FROMDATE to an output parameter TODATE, based on the values of
the FROMFORMAT and TOFORMAT parameters.

The SPL declaration of the procedure is as follows:

     +---------------------------------------------------------+
     |                                                         |
     |PROCEDURE CONVERTDATE (FROMDATE, TODATE,                 |
     |                       FROMFORMAT, TOFORMAT, DATELENGTH);|
     |          VALUE        FROMFORMAT, TOFORMAT, DATELENGTH; |
     |          BYTE ARRAY   FROMDATE, TODATE;                 |
     |          INTEGER      FROMFORMAT, TOFORMAT, DATELENGTH; |
     |                                                         |
     +---------------------------------------------------------+

The DATELENGTH parameter contains the number of bytes in the date.

The FROMFORMAT, TOFORMAT, and DATELENGTH parameters are declared to be
value parameters, while FROMDATE and TODATE are passed by reference.

Because the CONVERTDATE procedure resides in a CM SL, you can write a
Switch stub that calls the HPSWITCHTOCM intrinsic, which, in turn, calls
CONVERTDATE.

Figure 3.2 illustrates the purpose of the CONVERTDATE Switch stub.

[]
Figure 3.2. HPSWITCHTOCM Example, CONVERTDATE Recall that Switch stubs make the mixed-mode calling process transparent to the calling program so that program need not change. This is possible because the stub procedure name is identical to the CM target procedure name, and the stub procedure parameters and their types are also identical to those of the target procedure. This allows the recompiled application to continue to call CONVERTDATE without any changes to the source code of the application. The following sample procedure declarations demonstrate these aspects of achieving mixed-mode calling transparency. The first extract is the declaration portion of an SPL procedure in the CM SL: +---------+ +-| MPE V/E |---------------------------------------------+ | +---------+ | | | |PROCEDURE CONVERTDATE (FROMDATE, TODATE, | | FROMFORMAT, TOFORMAT, DATELENGTH);| | VALUE FROMFORMAT, TOFORMAT, DATELENGTH; | | BYTE ARRAY FROMDATE, TODATE; | | INTEGER FROMFORMAT, TOFORMAT, DATELENGTH; | | | | | +---------------------------------------------------------+ The second extract is the HP Pascal/XL declaration portion of a Switch stub that enables you to call the corresponding CM SL procedure: +--------+ +-| MPE XL |----------------------------------------------+ | +--------+ | | | |TYPE | | DATE_BUFFER : PACKED ARRAY [1..80] OF CHAR; | | | | | |PROCEDURE CONVERTDATE(VAR FROMDATE, TODATE : DATE_BUFFER;| | FROMFORMAT, TOFORMAT, DATELENGTH : SHORTINT);| | | | | | | +---------------------------------------------------------+ Note the ways in which the MPE XL declaration makes the stub and the switching process transparent to any program that calls the SPL procedure: * The Switch stub procedure name is identical to that of the SPL procedure. * The types of the Switch stub parameters are declared to correspond to those of the SPL procedure: * Value parameters correspond to value parameters; likewise, reference parameters correspond. * The data types of the corresponding parameters are compatible. Another responsibility of the Switch stub is to set up the parameters required by the appropriate Switch intrinsic. In this instance, that is the HPSWITCHTOCM intrinsic. Here, again, is a sample call to HPSWITCHTOCM: HPSWITCHTOCM(proc, method, numparms, parms, funcreturnlen, funcvalue, conditioncode, userstatus) The parameters that the CONVERTDATE Switch stub must set up before it can call the HPSWITCHTOCM intrinsic convey to Switch the following information: * Name and CM library or plabel of the target procedure. * Whether the target procedure runs in normal, split-stack, or no-copy mode. * Number of parameters being passed to the target procedure. * Array of records, each containing a description of one parameter being passed, including: * Pointer to the parameter; that is, a reference to where the parameter begins in NM memory. Value parameters larger than one byte must be 16-bit aligned. * Length (size) of the parameter in bytes (must be positive integer <= 2 ** 16). * For reference parameters, the stub must specify either a byte or word address and also indicate whether the parameter is an input and/or output parameter. * Length of the function return value (0 if not a function). * Pointer to the function return value (nil if not a function). * CM condition code value to be returned from the target procedure. * Status record to report on HPSWITCHTOCM's operation. In the course of Example 3-1A, the necessary constants, types, and variables are declared. The body of the stub follows in Example 3-1B. Examples 3-1A and 3-1B together constitute the CONVERTDATE stub. Example 3-1A. Declarations Portion of CONVERTDATE Stub $standard_level 'EXT_MODCAL'$ $subprogram$ $os 'MPE/XL'$ Program XAMPL31A(input, output); const { * * * PROC parameter * * * } {The OS finds procedures by number, by name, or by plabel} pidt_known = 0; {it is found by number } pidt_load = 1; {it is found by name } pidt_plabel = 2; {it is specified by its CM plabel} {Which library is the procedure in?} system_sl = 0; logon_pub_sl = 1; logon_group_sl = 2; pub_sl = 3; group_sl = 4; {max CM procedure name length} length_cm_proc_name = 16; type bit8 = 0..255; bit16 = 0..65535; bit8_a1 = $ALIGNMENT 1$ bit8; bit16_a1 = $ALIGNMENT 1$ bit16; {type declaration for procedure names} cm_proc_name = packed array [1..length_cm_proc_name] of char; {defining type of HPSWITCHTOCM proc parameter} scm_procedure = packed record case p_proc_id_type : bit8 of {proc found by number} pidt_known : ( p_fill : bit8_a1; p_proc_id : bit16_a1 ); {proc found by name} pidt_load : ( {system, pub, or group library} p_lib : bit8_a1; {ASCII name left justified & blank padded} p_proc_name : cm_proc_name); {proc found by proc's CM plabel} pidt_plabel : ( p_plabel : bit16_a1); end; Example 3-1A. Declarations Portion of CONVERTDATE Stub, continued const { * * * METHOD parameter * * * } {defining HPSWITCHTOCM method parameter} method_normal = 0; {non-split-stack} method_split = 1; {if all parameters within cm stack or ref parm length < threshold then use method_normal else wrap ref parms in extra data segment } method_no_copy = 2; {use split stack if ref parms outside of cm stack } const { * * * NUM_PARMS parameter * * * } max_target_parms = 32; {max # of target parameters} const { * * * PARMS parameter * * * } {What is the parameter type?} parm_type_value = 0; {value parameter } parm_type_word_ref = 1; {word address is required} parm_type_byte_ref = 2; {byte address is required} type {defining type of indicator as byte or word address} scm_parm_type = bit16; {defining type of indicator as input and/or output } {parameter } scm_io_type = set of ( INPUT_PARM, OUTPUT_PARM ); {defining individual record of HPSWITCHTOCM parms } {parameter; parms is array describing the stub } {parameters; each record describes a parameter } parm_desc = packed record pd_parmptr : globalanyptr; {where parameter found} pd_parmlen : bit16; {size in bytes} pd_parm_type : scm_parm_type; {value parm or byte or word address reference parm} pd_io_type : scm_io_type; {input and/or output} end; {defining type of HPSWITCHTOCM parms parameter} scm_parm_desc_array = array [1..max_target_parms] of parm_desc; Example 3-1A. Declarations Portion of CONVERTDATE Stub, continued const { * * * CONDITION_CODE parameter * * * } ccg = 0; ccl = 1; cce = 2; type ccode_type = shortint; const { * * * STATUS constant * * * } all_ok = 0; {used in status check} type { * * * STATUS parameter * * * } xlstatus = record case integer of 0 : (all : integer); 1 : (info : shortint; subsys : shortint); end; type { * * * Switch stub parameters * * * } date_buffer = packed array[1..80] of char; {declaring intrinsic procedures -- externals} procedure HPSWITCHTOCM; intrinsic; procedure HPSETCCODE; intrinsic; procedure QUIT; intrinsic; {declaring Switch stub header} procedure CONVERTDATE (var FROMDATE, TODATE : date_buffer; FROMFORMAT, TOFORMAT, DATELENGTH : shortint); var proc : scm_procedure; {target proc name} parms : scm_parm_desc_array; {describes target proc's parameters} method : integer; {method of call} nparms : integer; {# of target's parameters} Example 3-1A. Declarations Portion of CONVERTDATE Stub, continued {declaring return parameters} funclen : integer; {length of return value} funcptr : integer; {pointer to return value} cond_code : ccode_type; {how condition code returned} status : xlstatus; {how MPE XL returns warnings} {declaring local variables} loc_fromformat : bit16; { FROMFORMAT } loc_toformat : bit16; { TOFORMAT } loc_datelength : bit16; { DATELENGTH } {end example 3-1A, completing the declaration portion} Example 3-1B. Body of CONVERTDATE Stub begin {format and length parameters are copied into local variables; local copies used since first 4 parms of proc are put in registers; Switch wants address but value in register won't have address; to get address, you must make local copy} loc_fromformat := FROMFORMAT; loc_toformat := TOFORMAT; loc_datelength := DATELENGTH; {the Switch variables are initialized} proc.p_proc_id_type := pidt_load; {find proc by name} proc.p_lib := pub_sl; {look in PUB SL (LIB=P)} proc.p_proc_name := 'CONVERTDATE '; {procedure name} method := method_normal; {NOT split-stack callable} nparms := 5; {number of parameters} {unless option variable, when option} {variable, add 1 to nparms } funclen := 0; {not a function--no return value} funcptr := 0; {not a function--no return value} {In the next sequence, "describe" involves the following:} { 1) give a pointer to the parameter's location } { 2) give the length (size) of the parameter } { 3) indicate whether value or reference parameter} { IF a reference parameter, THEN } { 4) indicate whether input and/or output parameter} {describe FROMDATE -- input by reference} {determine pointer to parameter's location; addr } {function takes parameter as argument and returns address} parms[1].pd_parmptr := addr(FROMDATE); {determine length of parameter; } {sizeof function takes parameter as argument and returns} {number of bytes in parameter } parms[1].pd_parmlen := sizeof(FROMDATE); {reference parameter requiring byte address} parms[1].pd_parm_type := parm_type_byte_ref; {input parameter} parms[1].pd_io_type := [input_parm]; Example 3-1B. Body of CONVERTDATE Stub, continued {describe TODATE -- output by reference} {determine pointer to parameter's location; addr } {function takes parameter as argument and returns address} parms[2].pd_parmptr := addr(TODATE); {determine length of parameter; } {sizeof function takes parameter as argument and returns} {number of bytes in parameter } parms[2].pd_parmlen := sizeof(TODATE); {reference parameter requiring byte address} parms[2].pd_parm_type := parm_type_byte_ref; {output parameter} parms[2].pd_io_type := [output_parm]; {describe TOFORMAT -- input by value} {determine pointer to parameter's location; addr } {function takes parameter as argument and returns address} parms[3].pd_parmptr := addr(loc_toformat); {determine length of parameter; } {sizeof function takes parameter as argument and returns} {number of bytes in parameter } parms[3].pd_parmlen := sizeof(TOFORMAT); {value parameter} parms[3].pd_parm_type := parm_type_value; {input parameter} parms[3].pd_io_type := [input_parm]; {describe FROMFORMAT -- input by value} {determine pointer to parameter's location; addr } {function takes parameter as argument and returns address} parms[4].pd_parmptr := addr(loc_fromformat); {determine length of parameter; } {sizeof function takes parameter as argument and returns} {number of bytes in parameter } Example 3-1B. Body of CONVERTDATE Stub, continued parms[4].pd_parmlen := sizeof(FROMFORMAT); {value parameter} parms[4].pd_parm_type := parm_type_value; {input parameter} parms[4].pd_io_type := [input_parm]; {describe DATELENGTH -- input by value} {determine pointer to parameter's location; addr } {function takes parameter as argument and returns address} parms[5].pd_parmptr := addr(loc_datelength); {determine length of parameter; } {sizeof function takes parameter as argument and returns} {number of bytes in parameter } parms[5].pd_parmlen := sizeof(DATELENGTH); {value parameter} parms[5].pd_parm_type := parm_type_value; {input parameter} parms[5].pd_io_type := [input_parm]; {call the Switch intrinsic to change modes} HPSWITCHTOCM (proc, method, nparms, parms, funclen, funcptr, cond_code, status ); {test MPE XL status value and set ccode if not OK } {HPSETCCODE intrinsic used to pass on result of CM } {call made by stub; calling program checks returned} {ccode } if status.all = all_ok then HPSETCCODE(cond_code) {from CM proc } else QUIT(status.info); {Switch subsystem error} end; {Stub procedure CONVERTDATE} BEGIN {dummy outer block} END. {end example 3-1B}
NOTE For a complete analysis of NM-to-CM Switch stub code, refer to Chapter 5.
Figure 3.3 illustrates how your CONVERTDATE Switch stub fits into the flow of control and enables you to access your CM SL CONVERTDATE procedure:
[]
Figure 3.3. NM--> CM Switch Summary 2 Example 3-2 implements a Switch stub for the BINARY intrinsic. This example illustrates a stub for a target procedure that has a functional return value:
NOTE This BINARY stub is only an example. The BINARY intrinsic is directly accessible from both Compatibility Mode and Native Mode, without the need of writing a stub to gain access.
Example 3-2. BINARY Intrinsic Switch Stub $subprogram$ $standard_level 'EXT_MODCAL'$ $tables off$ $code_offsets off$ $xref off$ $type_coercion 'representation'$ $os 'MPE/XL'$ PROGRAM XAMPL32(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} 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; Example 3-2. BINARY Intrinsic Switch Stub, continued 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; {record} PROCEDURE HPSWITCHTOCM; INTRINSIC; PROCEDURE HPSETCCODE; INTRINSIC; PROCEDURE QUIT; INTRINSIC; {End of OUTER BLOCK GLOBAL declarations} Example 3-2. BINARY Intrinsic Switch Stub, continued FUNCTION BINARY $ALIAS 'BINARY'$ ( ANYVAR F1 : GENERIC_BUFFER; F2 : SHORTINT; ) : SHORTINT OPTION UNCHECKABLE_ANYVAR; VAR proc : SCM_PROCEDURE; parms : SCM_PARM_DESC_ARRAY; method : INTEGER; nparms : INTEGER; funclen : INTEGER; funcptr : INTEGER; byte_len_of_parm : BIT16; cond_code : CCODE_TYPE; status : XLSTATUS; VAR loc_F2 : SHORTINT; funcval : SHORTINT; begin {STUB procedure BINARY } { Initialization } { Setup procedure information -- name, lib, etc} proc.p_proc_id_type := Pidt_Name; {by name} proc.p_lib := Pub_Sl; {library} proc.p_proc_name := 'BINARY '; {Setup misc. variables} method := Method_Normal; {Switch copy mode} nparms := 2; {Setup 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(funcval); {A function} funcval := 0; funcptr := INTEGER(LOCALANYPTR(ADDR(funcval))); {Make a local copy of all VALUE parameters } loc_F2 := F2; Example 3-2. BINARY Intrinsic Switch Stub, continued {Build parameter descriptor array to describe each } {parameter. } {F1 -- Input Only by Reference } byte_len_of_parm := F2 * 1; parms[0].pd_parmptr := ADDR(F1); parms[0].pd_parmlen := byte_len_of_parm; parms[0].pd_parm_type := Parm_Type_Byte_Ref; parms[0].pd_io_type := [Input_Parm]; {F2 -- Input Only by Value } byte_len_of_parm := 2; parms[1].pd_parmptr := ADDR(loc_F2); parms[1].pd_parmlen := byte_len_of_parm; parms[1].pd_parm_type := Parm_Type_Value; parms[1].pd_io_type := [Input_Parm]; {Do actual Switch call} HPSWITCHTOCM (proc, {procedure info} method, {Switch copy method} nparms, {Number of parameters} parms, {Parm descriptor array} funclen, {Function return value length} funcptr, {Address of functional return} cond_code, {Condition code return} status); {Switch status code} binary := 0; if (status.all <> all_ok) then BEGIN {Switch subsystem error} QUIT(status.info); END {Switch subsystem error} else binary := funcval; HPSETCCODE(cond_code); END; {STUB procedure} BEGIN {Program Outer Block code} END. {Program Outer Block code} {end Example 3-2}


MPE/iX 5.0 Documentation