Switch Programing Guide HP 3000 Computer Systems ABCDE HP Part No. 32650-90014 Printed in U.S.A.
The information contained in this document is subject to change without notice. HEWLETT-PACKARD MAKES NO WARRANTY OF ANY KIND WITH REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Hewlett-Packard shall not be liable for errors contained herein or for incidental or consequential damages in connection with the furnishing, performance or use of this material.
PRINTING HISTORY New editions are complete revisions of the manual. Update packages, which are issued between editions, contain additional and replacement pages to be merged into the manual by the customer. The dates on the title page change only when a new edition or a new update is published. No information is incorporated into a reprinting unless it appears as a prior update; the edition does not change when an update is incorporated.
CONVENTIONS USED IN THIS MANUAL NOTATION COMMAND KEYWORDS parameter parameter [] DESCRIPTION Commands are shown in CAPITAL LETTERS. The names must contain no blanks and be delimited by a non-alphabetic character (usually a blank). Literal keywords, which are entered optionally but exactly as speci ed, appear in CAPITAL LETTERS. Required parameters, for which you must substitute a value, appear in bold italics . Optional parameters, for which you may substitute a value, appear in standard italics .
... user input An ellipsis indicates that a previous bracketed element may be repeated, or that elements have been omitted. In examples of interactive dialog, user input is underlined. Example: NEW NAME? ALPHA1 superscriptc Control characters are indicated by a superscriptc . 4RETURN5 Example: Yc . (Press Y and the CNTL key simultaneously.) 4RETURN5 indicates the carriage return key.
Contents 1. Introduction Native Mode (NM) . . . . . . . . . . . . . . . . . Full Recompilation . . . . . . . . . . . . . . . . Advantages . . . . . . . . . . . . . . . . . . . Considerations . . . . . . . . . . . . . . . . . . Compatibility Mode . . . . . . . . . . . . . . . . . Emulator . . . . . . . . . . . . . . . . . . . . Object Code Translator . . . . . . . . . . . . . . Emulation and Translation Considerations . . . . . . Summarizing NM-only and CM-only Execution . . . . .
2. Simplifying Switch Programming SWitch Assist Tool (SWAT) . . . . . . . . . . . . . . . . Who Uses SWAT? . . . . . . . . . . . . . . . . . . . Features . . . . . . . . . . . . . . . . . . . . . . . . Bene ts . . . . . . . . . . . . . . . . . . . . . . . . Switch Stub Operation . . . . . . . . . . . . . . . . . Generating Switch Stubs Automatically . . . . . . . . . . . Invoking SWAT . . . . . . . . . . . . . . . . . . . . . What SWAT Needs to Know . . . . . . . . . . . . . . .
ARRAYLEN Menu Function Keys . . . . . . . . . . . Completing the ARRAYLEN Menu . . . . . . . . . . . HELP Screens . . . . . . . . . . . . . . . . . . . . . MAIN Menu HELP Screen . . . . . . . . . . . . . . . PROCINFO Menu HELP Screen . . . . . . . . . . . . PARMINFO Menu HELP Screen . . . . . . . . . . . . ARRAYLEN Menu HELP Screen . . . . . . . . . . . . COMMIT Screen . . . . . . . . . . . . . . . . . . . . PROGRESS MESSAGES Screen . . . . . . . . . . . . . Completion of Stub Generation . . . . . . . . . .
Syntax . . . . . . . . . . . . . Parameters . . . . . . . . . . . . Examples: NM to CM and Return . . Switch to CM Sequence . . . . . . . Special Considerations and Restrictions General . . . . . . . . . . . . . NM|> CM . . . . . . . . . . . Testing and Debugging Considerations . 4. 5. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Declaring Called External Procedures . . . Writing the DECMADD Stub Body . . . . . Finished DECMADD Stub . . . . . . . . . Checklist for Writing NM|> CM Switch Stubs Switching to NM . . . . . . . . . . . . . Writing the CMCICommand Stub Declarations Declaring the Stub Header . . . . . . . . Declaring the Stub Parameters . . . . . . Declaring User-De ned Types . . . . . Declaring Variables . . . . . . . . . . Declaring Called External Procedures . . . Writing the CMCICommand Stub Body . . .
Figures 1-1. 1-2. 1-3. 1-4. 1-5. 1-6. 1-7. 1-8. 1-9. 1-10. 1-11. 1-12. 1-13. 1-14. 1-15. 1-16. 2-1. 2-2. 2-3. 2-4. 2-5. 2-6. 2-7. 2-8. 2-9. 2-10. 2-11. 2-12. 3-1. 3-2. MPE XL Execution Environment . . . . . . . OCT Translation Process . . . . . . . . . . Switch in MPE XL Execution Environment . . Compatibility Mode Execution Model . . . . . Native Mode Execution Model . . . . . . . . CM|> NM Mixed-mode Execution Model . . . NM|> CM Mixed-mode Execution Model . . .
3-3. 4-1. 4-2. 4-3. 4-4. 4-5. NM|> CM Switch Summary 2 . . . . . CM|> NM Switch Summary 1 . . . . . ARGDESC and ARGLIST Arrays . . . . Supported Function Type Mappings . . . . HPSWTONMNAME Example, CMDeleteVar CM|> NM Switch Summary 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Tables 2-1. 3-1. 3-2. 3-3. 3-4. 4-1. 4-2. 4-3. Number of Allowed Array Elements By Type . . . . . . . . Data Alignment By XL Language . . . . . . . . . . . . . HPSWITCHTOCM Status Returns (Page 1) . . . . . . . . CM Loader Status Returns (Page 1) . . . . . . . . . . . . Table 3-3. CM Loader Status Returns (Page 4) . . . . . . . Parameter Type IDs and Their NM/CM Sizes . . . . . . . SPL|> HP Pascal/XL Parameter Type Mappings . . . . . Pascal/V|> HP Pascal/XL Parameter Type Mappings (Page 1) . . . . . . . .
1 Introduction Through a simple STORE/RESTORE process, you can move nonprivileged MPE V/E applications to MPE XL-based machines without modi cation, conversion, or recompilation.
Vastly increased stack/code/data space The 900 Series systems run MPE XL, an extended version of the MPE V/E operating system. Full Recompilation After moving MPE V/E programs over to MPE XL, you will ultimately want to take advantage of the optimizing NM compilers. Recompilation can involve source code changes, especially if your application calls routines in languages not supported in Native Mode or uses MPE V/E features deleted from, or no longer available on, MPE XL.
Compatibility Mode Compatibility Mode (CM) is an emulation of the MPE V/E operating environment. Consequently, it is very compatible with HP 3000 object code from MPE V/E-based systems, allowing applications newly restored from MPE V/E-based systems to run immediately and transparently on 900 Series HP 3000s (with certain exceptions, as noted below in \Emulation and Translation Considerations"). Compatibility Mode is available to simplify the migration to the 900 Series of the HP 3000 family.
Emulator Under MPE XL, HP 3000 Compatibility Mode is implemented as an emulator for the CPU of MPE V/E-based systems and as an interface between supported MPE V/E intrinsic calls and MPE XL intrinsics. The Emulator functions as an object code interpreter.
Emulation and Translation Considerations A code size expansion occurs when translating MPE V/E-based object code to its 900 Series equivalent using the Object Code Translator. You have a choice between higher performance execution using the Object Code Translator or more e cient disc space utilization using the Emulator. Another tradeo involves the ease of debugging. Since original MPE V/E program les are unchanged when emulated, they can be debugged using the CM portion of the MPE XL Debugger.
XL operating system software itself. Hewlett-Packard will investigate and attempt to resolve problems resulting from the use of Privileged Mode code. This service, which is not provided under the standard service contract, is available on a time and materials billing basis. Hewlett-Packard will not support, correct, or attend to any modi cation of the MPE XL operating system software.
Figure 1-1.
The translated program in Figure 1-1 is the result of a one-time translation process illustrated in Figure 1-2. The translation process is invoked by issuing the command: :OCTCOMP CMprogname .
Figure 1-2.
Mixed-mode Procedure Calling (Partial Recompilation) Partial recompilation, possibly requiring rewriting, employs the Switch subsystem (Switch) to make mixed-mode procedure calls. The MPE XL Switch subsystem (Switch) provides the ability for programs executing in one mode to call Compatibility Mode (CM) Segmented Library (SL) or Native Mode (NM) Executable Library (XL) procedures that reside in the opposite mode.
Figure 1-3.
Mixed-mode Overview MPE XL-based systems provide two operating modes (Compatibility Mode and Native Mode) and a variety of execution options: 1. You can run CM programs (directly after being restored from your MPE V/E STORE tape), and, from that code, call procedures that are located in a CM SL. In this instance, all execution is within Compatibility Mode, and no apparent mode switching on the part of your program is involved. Figure 1-4 illustrates this model.
Figure 1-4.
2. You can run NM programs (after full recompilation), and, from that code, call procedures that are located in an NM Executable Library. In this instance, all execution is within Native Mode, and again no apparent mode switching on the part of your program is involved. This is demonstrated in Figure 1-5.
Figure 1-5.
3. When running NM code you can call procedures located in a CM SL, or when running CM code you can call procedures located in an NM Executable Library. These situations involve mixed-mode procedure calls, and Switch provides such capability. Figures 1-6 and 1-7 symbolize this mixed-mode calling feature.
Figure 1-6.
Figure 1-7.
Note Combinations of mixed-mode procedure calls are also possible. For example, your NM program could use Switch to call a CM SL procedure that, in turn, could call an NM Executable Library procedure via Switch (NM|> CM|> NM), and so on. Conversely, your CM program could use Switch to call an NM Executable Library procedure that, in turn, could call a CM SL procedure via Switch (CM|> NM|> CM), and so on.
it is able to take particular advantage of that architecture. However, SPL is so architecture-dependent that it has not been migrated to Native Mode. Consequently, the user of SPL procedures is faced with two options: 1. Rewrite all SPL procedures in higher-level languages that can be compiled directly in Native Mode. 2.
types of systems and the attendant need to convert between MPE V/E- and MPE XL-based data may make migration an ongoing concern. Cost/Performance Factors As noted previously, you have the ability to run applications in Compatibility Mode, Native Mode, or mixed modes. To some extent, the choice of how to mix execution modes may involve the question of how to achieve the best possible performance.
Figures 1-8 and 1-9 demonstrate the role of the Switch intrinsics in the process of carrying out mixed-mode procedure calls: Figure 1-8.
Figure 1-9.
Purpose Due to architectural di erences between MPE V/E- and MPE XL-based systems, programs that switch between CM and NM execution may encounter di erences in data representation. The primary purpose of Switch is to resolve this situation by providing mixed-mode execution access and parameter translation between Compatibility Mode and Native Mode.
Switch to CM Overview Figure 1-10 represents the process of mixed-mode procedure calling in the NM|> CM direction.
Figure 1-10.
A mixed-mode procedure call in the direction NM|> CM involves the following steps, as indicated in Figure 1-10: 1. The NM code needing to access a CM routine calls a Switch intrinsic, either by means of in-line code or a Switch stub. 2. The in-line code or NM Switch stub sets up the data structures and parameters required by Switch and makes a call to the HPSWITCHTOCM intrinsic (call by name), or the HPLOADCMPROCEDURE and HPSWITCHTOCM intrinsics (call by plabel). 3.
Figure 1-11.
A mixed-mode procedure call in the direction CM|> NM involves the following steps, as indicated in Figure 1-11: 1. The CM code needing to access an NM routine calls Switch, either by means of in-line code or a Switch stub. 2. The in-line code or CM Switch stub sets up the data structures and parameters required by Switch and makes a call to either the HPSWTONMNAME intrinsic or the HPLOADNMPROC and HPSWTONMPLABEL intrinsics. 3.
Switch Stubs A Switch stub is a routine that acts as a facade, hiding the complexity of the actual Switch call. The primary purpose of Switch stubs is to provide applications that must call routines residing in an other-mode library with transparent access to Switch. Transparency for the application making the mixed-mode call means that the recompiled calling program usually does not require source changes to call procedures from its original mode.
Operation The Switch stub is responsible for doing the following: Setting up the data structures and parameters required by Switch intrinsics Making the call to the Switch intrinsic, which translates and copies parameters as required and triggers the change in operating mode Retranslating the parameters that the mixed-mode procedure call returns through Switch Setting the condition code on return from the NM routine (CM|> NM only) Error handling Switch makes the data and parameters of the calling procedure
loader resolves an external reference made in one mode to an executable library in the opposite mode, because object le formats for the two processors are very di erent. Explicit calls to Switch intrinsics resolve such external references by identifying the le from which to load the procedure and providing the information needed to translate parameters. This is possible because one of the parameters passed to the Switch intrinsic designates the library in which the external procedure can be found.
1. 2. 3. 4. 5.
Generate Switch calls (either via in-line code or Switch stubs linked with the new NM programs) to CM procedures Those in the fourth category should do the following: Write NM procedures to replace performance-critical CM procedures and place them in an Executable Library Generate CM|> NM Switch calls (through in-line code or Switch stubs) to these NM procedures Those in the nal category should do the following: Generate the appropriate NM|> CM Switch calls (coded in-line or in Switch stubs) Generate the ap
Figure 1-12.
Figure 1-13.
The following series of gures illustrates the migration of an existing COBOL II/V application to Native Mode. You can simply do a STORE/RESTORE to move the application. For even greater performance in Native Mode, you can recompile the source, taking advantage of the NM compilers. However, this application calls an SPL procedure that cannot be migrated to Native Mode. Therefore, you must use Switch to access this SPL procedure (if you do not want to rewrite it in an NM high-level language).
Figure 1-14.
Figure 1-15.
Figure 1-16.
2 Simplifying Switch Programming Tools have been developed to facilitate the migration process. Among these tools is one that, in most instances, can simplify use of the Switch subsystem (Switch), when switching from Native Mode to Compatibility Mode. SWitch Assist Tool (SWAT) The SWitch Assist Tool (SWAT) is an interactive utility that produces the Switch stub source code you can use to make mixed-mode procedure calls in the NM|> CM direction.
Figure 2-1. Mixed-mode Procedure Call Procedure Z represents an entity that is not supplied in the Native Mode environment. The SWAT utility can help you handle such unresolved references. Tools like SWAT enable you to improve performance of migrated applications with a minimum of e ort and concern about the architectural di erences. You can use SWAT prior to installation to prepare the source code for Switch stubs ahead of time, as well as after the MPE XL-based system is up and running.
phased approach. That requires the mixing of Compatibility Mode and Native Mode code. Switch provides the ability to make mixed-mode procedure calls. SWAT helps you use Switch to run portions of an application in Compatibility Mode and portions in Native Mode. You will be particularly interested in using SWAT if you have high-level applications that call user-written SPL routines or if your applications call SPL routines for which the source code is not available.
Benefits SWAT's primary bene t is the programmer support it provides by alleviating much of the complexity faced in making mixed-mode procedure calls. It also increases the quality of Switch stub source code by generating standardized source code.
For those who prefer to code Switch stubs manually, or in some instances must do so, SWAT provides examples of good coding practices and can act as a template for advanced stubs.
Figure 2-2.
The Switch stub acts as an interceptor/intermediary that calls the Switch subsystem and passes it the parameters of the called procedure and any other information required by Switch. Switch itself calls the other-mode procedure.
stub object code. For more information on how to invoke this compiler, see the discussion of the PASXL command in the MPE XL Commands Reference Manual (32650-90003). Compilation of that source must be on an MPE XL-based machine. The resulting object code is input to the MPE XL Link Editor, where you can either install the object code in an NM Executable Library or link it into an NM program le. For more information on the Link Editor, refer to Link Editor/XL Reference Manual (32650-90030).
Note The process of gathering information about parameters is iterative. How SWAT Obtains Information When you run SWAT, SWAT uses VPLUS screens to prompt you for this required information. There are a total of seven screens that you may encounter as you enter the information required by SWAT, request help on how to complete a form screen, edit forms or con rm your satisfaction with the completed forms, and await the result of the stub generation process.
After generation of Switch stub source code is complete, the MAIN menu screen reappears, allowing you to build another stub or to exit SWAT and return to the system Command Interpreter. Inputting Information You move from eld to eld and item to item within a menu by means of the Cursor Control keys or the Tab key. To complete some elds, you must enter a name or numerical value. In other instances, the eld consists of a list of options.
message appropriate to that error appears at the bottom of the screen. In this way, the tool guides you through the correction process. When the last error is resolved, the Switch Assist Tool records your entries when you press 4Enter5 and brings up the next menu. MAIN Menu Screen The MAIN menu screen is the rst to appear upon invoking SWAT.
maximum of 32 characters long. You may leave these elds blank, indicating that the target procedure has no parameters. Note Procedure and parameter names are not localizable. They are limited to the alphanumeric characters of the English alphabet. All entries are checked for validity. However, the Switch Assist Tool does not check for use of HP Pascal/XL reserved words and prede ned routines as names.
Figure F02-03 here. Figure 2-3. MAIN Menu Screen MAIN Menu Function Keys There are several function key options available to you on the MAIN menu screen: Press F4 to refresh the screen. Press F6 to proceed to the next menu (used for reviewing and editing menu contents).
Press F7 to view the HELP screen on the MAIN menu. Press F8 to exit SWAT and return to the system Command Interpreter. Caution Pressing F8 at any time returns you immediately to the system prompt, causing you to lose any information entered up to that point. Completing the MAIN Menu Screen To input the information entered on the menu to SWAT and initiate error-checking, press the 4Enter5 key. The process of correcting MAIN menu errors is the same as that described in \Resolving Errors".
Designating the Location of the Target Procedure The target procedure must be located in some CM Segmented Library (SL). This may be the system library, an account library, or a group library. If you specify the system library, only the system SL is searched. If you specify an account library, the account library is searched rst, then the system library. Finally, if you specify a group library, the group library is searched rst, followed in turn by that group's account library and the system library.
Since this code is a ected by many processes, you should check its value immediately upon return from a process. To return the condition code from the target CM routine, select the YES, RETURN CONDITION CODE option on the PROCINFO screen. Figure 2-4 provides an example of the PROCINFO menu screen. re F02-04 here. Figure 2-4.
PROCINFO Menu Function Keys There are several function key options available to you on the PROCINFO menu screen: Press F1 to return to the MAIN menu. Press F4 to refresh the screen. Press F5 to go back to the previous menu. Press F6 to proceed to the next menu (for reviewing/editing information, not recording it). Press F7 to view the HELP screen on the PROCINFO menu. Press F8 to exit SWAT and return to the system Command Interpreter.
Whether the parameter is an array The appropriate legal options are provided on the PARMINFO menu. You can select one value for each eld. You make your selection by placing a nonblank character in the space provided next to the appropriate value. You cannot leave any of the elds blank. If you do so, the cursor is repositioned at the blank eld. SWAT also checks that you have not speci ed a multi-element item as a value parameter.
Designating Whether a Parameter Is an Array You must indicate whether a parameter is an array. You do so by designating the appropriate option in the ARRAY SPECIFICATION eld. If you indicate that a parameter is an array, the ARRAYLEN menu screen subsequently appears to collect information about the length of the array parameter. A sample PARMINFO menu screen appears in Figure 2-5. Figure F02-05 here. Figure 2-5.
PARMINFO Menu Function Keys There are several function key options available to you on the PARMINFO menu screen: Press F1 to return to the MAIN menu. Press F4 to refresh the screen. Press F5 to go back to the previous screen. Press F6 to proceed to the next screen (for reviewing/editing information, not recording it). Press F7 to view the HELP screen on the PARMINFO menu. Press F8 to exit SWAT and return to the system Command Interpreter.
Designating the Length Value of an Array Parameter You have two options when specifying the length (size) of an array parameter. One way is to designate a speci c constant value in the range of 1 to 65,535. If that is your choice, enter a decimal number in the space provided. The number of array elements allowed depends on the SPL data type in the target CM array parameter. Table 2-1 lists the allowed array element ranges for the various SPL data types. Table 2-1.
If the parameter has a positive value, that value represents the size as the number of elements. If the value of the parameter is negative, the parameter represents the size as the number of bytes. Select the appropriate option by placing a nonblank character in the space provided next to your choice. Caution If you specify an array size larger than its declared size, unpredictable results occur when the stub is executed. A sample ARRAYLEN menu screen appears in Figure 2-6.
Figure F02-06 here. Figure 2-6.
ARRAYLEN Menu Function Keys There are several function key options available to you on the ARRAYLEN menu screen: Press F1 to return to the MAIN menu. Press F4 to refresh the screen. Press F5 to go back to the previous screen. Press F6 to proceed to the next screen (for reviewing/editing information, not recording it). Press F7 to view the HELP screen on the ARRAYLEN menu. Press F8 to exit SWAT and return to the system Command Interpreter.
Name of the target procedure Name(s) of the parameters of the target procedure (up to 32) d Figure 2-7 illustrates the appearance of the introductory MAIN menu HELP screen. The MAIN screen gathers the following global information: a * the name of the file to hold the source code produced by the Switch Assist Tool * the name of the target procedure you want to call in the Compatibility Mode (CM) environment * the names of the target procedure's parameters (up to 32) From 1. 2. 3. 4. 5.
Privilege level of the target procedure Whether the target procedure returns a condition code Figure 2-8 illustrates the appearance of the introductory PROCINFO menu HELP screen. The PROCINFO screen collects information about the procedure you want to call in the Compatibility Mode environment.
I/O type of a parameter Whether the parameter is an array and, if so, how many elements are in that structure d Figure 2-9 illustrates the appearance of the introductory PARMINFO menu HELP screen. The PARMINFO screens collect information concerning the parameters to be passed to the routine you want to call in the Compatibility Mode environment.
How the array length value (either a constant value or a parameter name) should be interpreted Figure 2-10 illustrates the appearance of the introductory ARRAYLEN menu HELP screen. The ARRAYLEN screens collect information concerning the arrays to be passed to the routine you want to call in the Compatibility Mode environment. The array information required by the Switch Assist Tool includes the following: * * a the length of the array parameter how the length value should be interpreted From 1. 2. 3. 4.
Press F2 to commit your menu selections and allow SWAT to begin stub generation. Press F4 to refresh the screen. Press F5 to return to the previous screen. Press F7 to view the HELP screen that deals with the COMMIT screen. Press F8 to leave SWAT. These options let you decide whether SWAT should begin generating Switch stub source code or whether you need to edit information entered in the menu screens. Recall that the Previous (and Next) function keys allow you to review and edit any SWAT menu screen.
Figure F02-11 here. Figure 2-11. COMMIT Screen PROGRESS MESSAGES Screen The PROGRESS MESSAGES screen appears after you have committed your menu selections by means of the COMMIT screen. In addition to displaying the name of the stub procedure and the line number currently being processed, the PROGRESS MESSAGES screen has space to display any progress, result, or error messages that SWAT has to report as it generates the source code for the stub.
Figure F02-12 here. Figure 2-12. PROGRESS MESSAGES Screen Completion of Stub Generation After generation of Switch stub source code is complete, the MAIN menu screen reappears, allowing you to build another stub or to exit SWAT and return to the system Command Interpreter.
Modifying SWAT Output The output le generated by SWAT contains the compiler statements and external declarations necessary to permit compilation of the stub procedure source code as a single entity. However, for a variety of reasons, you may wish to modify this le. Because SWAT generates source code in a text le, you can use existing HP 3000 editors to modify the source produced by the tool.
For more information, refer to the discussion of the PASXL command in the MPE XL Commands Reference Manual (32650-90003). Compilation of that source must be on an MPE XL-based machine. The resulting object code is input to the MPE XL Link Editor, where you can either install the object code in an NM Executable Library for shared use or link it into an NM program le. Example 3-10 of this manual illustrates a sample LinkEdit session.
Note All of the above are part of the Fundamental Operating Software (FOS). To compile the source code generated by SWAT, you must have the HP Pascal/XL compiler. Example Source File Generated by SWAT The following is an example of the source code generated by SWAT. You can use this source to call an SPL function FREAD with three parameters FILENUMBER, TARGET, and TCOUNT. Note This FREAD stub is only an example.
{This program is an example program written by the (SWitch Assist Tool.
Hp_Pidt_Known : (Hp_p_fill Hp_p_proc_id ); Hp_Pidt_Name : (Hp_p_lib Hp_p_proc_name ); Hp_Pidt_Plabel: (Hp_p_plabel : END; {record} : : Hp_BIT8_A1; Hp_BIT16_A1 : Hp_BIT8_A1; : Hp_CM_PROC_NAME Hp_BIT16_A1); Hp_SCM_IO_TYPE = SET OF (Hp_input, Hp_output); Hp_PARM_DESC = PACKED RECORD Hp_pd_parmptr : GLOBALANYPTR; Hp_pd_parmlen : Hp_BIT16; Hp_pd_parmtype : Hp_BIT16; Hp_pd_io_type : Hp_SCM_IO_TYPE; END; {record} Hp_SCM_PARM_DESC_ARRAY = ARRAY[0..
PROCEDURE HPSETCCODE; INTRINSIC; PROCEDURE QUIT; INTRINSIC; {End of OUTER BLOCK GLOBAL declarations} FUNCTION FREAD $ALIAS 'FREAD'$ ( FILENUMBER : HP_SHORTINT; ANYVAR TARGET : Hp_GENERIC_BUFFER; TCOUNT : HP_SHORTINT ) : HP_SHORTINT OPTION UNCHECKABLE_ANYVAR; VAR Hp_proc : Hp_SCM_PROCEDURE; Hp_parms : Hp_SCM_PARM_DESC_ARRAY; Hp_method : INTEGER; Hp_nparms : INTEGER; Hp_funclen : INTEGER; Hp_funcptr : INTEGER; Hp_byte_len_of_parm : Hp_BIT16; Hp_cond_code : SHORTINT; Hp_status : Hp_STATUS_TYPE; VAR Hp_retval
{* *} {************************************************} {Initialization} {Set up procedure information--name, lib, etc.} Hp_proc.Hp_p_proc_id_type := Hp_Pidt_Name; Hp_proc.Hp_p_lib := Hp_System_SL; Hp_proc.Hp_p_proc_name := 'FREAD {by name} {library} '; {Set up misc. variables} Hp_method := Hp_Method_Normal; Hp_nparms := 3; {non-split-stack} {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.
{TARGET -- Output Only by REFERENCE} IF TCOUNT < 0 THEN Hp_byte_len_of_parm := ABS(TCOUNT) ELSE Hp_byte_len_of_parm := TCOUNT * 2; Hp_parms[1].Hp_pd_parmptr Hp_parms[1].Hp_pd_parmlen Hp_parms[1].Hp_pd_parm_type Hp_parms[1].Hp_pd_io_type := := := := ADDR(TARGET); Hp_byte_len_of_parm; Hp_Parm_Word_Ref; [Hp_output]; {TCOUNT -- Input Only by VALUE} Hp_byte_len_of_parm := 2; Hp_parms[2].Hp_pd_parmptr Hp_parms[2].Hp_pd_parmlen Hp_parms[2].Hp_pd_parm_type Hp_parms[2].
HPSETCCODE (Hp_cond_code); FREAD := Hp_retval; end; {STUB procedure FREAD} BEGIN {Program Outer block code} END. {Program Outer block code} SWAT Quick Reference Summary The following steps summarize the process of using SWAT to generate Switch stubs automatically and how to use SWAT-generated stubs: 1. To invoke SWAT, type: RUN SWAT.PUB.SYS. SWAT uses VPLUS screens to prompt you for the information it needs. 2. Follow these guidelines when lling in a menu: a.
4. Fill in SWAT's PROCINFO menu with the following information: Location of the target procedure Function return type of the target procedure Privilege level of the target procedure Whether the target procedure returns a condition code 5. For each parameter, ll in SWAT's PARMINFO menu with the following information: Parameter's addressing method Parameter's data type Parameter's I/O type Whether a parameter is an array 6.
12. Use the Link Editor to link the resulting object code into an NM program le or install it in an NM Executable Library. For more information on the Link Editor, refer to the Link Editor/XL Reference Manual (32650-90030). Special Cases There are certain situations that the Switch Assist Tool does not handle. Other situations require special consideration before you decide to use SWAT-generated Switch stubs. Note The following information applies only to switches in the NM| > CM direction.
where an application dictates that a pointer always points to a location within one of the other passed parameters, but you must handle those instances manually. Passing plabels across modes implies that you can transfer control across modes without using Switch. Since that is not the case, you cannot pass plabels as parameters. Caution Programming a correct and reliable split-stack Switch stub requires a very high level of knowledge about programming in both modes on MPE XL.
to the HPFPCONVERT intrinsic into the SWAT-generated stub. You may have to perform the conversion twice, once in preparation for the Switch and again upon returning from it. No conversion is necessary if the calling procedure has already done the conversion or if the caller used HP 3000 Mode oating-point format. Refer to the MPE XL Intrinsics Reference Manual (32650-90028) for information about HPFPCONVERT. Overlapping Reference Parameters If reference parameters overlap, unpredictable results can occur.
terminated by a carriage return (for example, the COMMAND intrinsic) or a binary zero (for example, the GENMESSAGE intrinsic). Or, as another option (using SWAT), you can take the length of the bu er from another parameter. In the case of FREAD/FWRITE, you specify the length in the call. On the PARMINFO screen, you supply the name of the parameter and then select the USE NEGATIVE = BYTES RULE option.
Assuming there is no such EXTERNAL declaration and the default value option works correctly, you can give reference parameters a default value of NIL. Since NIL is never a valid value for reference parameters, this provides an easy method for determining whether the parameter was passed. However, parameters passed by value can have any value since, unlike reference parameters, they do not have to be a valid address. This poses a major problem in distinguishing value parameters included in the call.
3 NM-to-CM Procedure Calls This section presents the following topics: Review of the ow of control in NM|> CM switches Details of NM|> CM switches, including their inner workings, syntax, parameters, and examples Special considerations and restrictions that apply to mixed-mode procedure calls Testing and debugging considerations This chapter provides the detailed reference information you will need if you write your own NM-to-CM Switch stubs.
Flow of Control: NM| > CM The ow of control for mixed-mode procedure calls in the direction NM|> CM is illustrated in Figure 3-1: Figure F03-01 here. Figure 3-1.
Stepwise Switch to CM A mixed-mode procedure call in the direction NM|> CM involves the following steps, as indicated in Figure 3-1: NM-to-CM Procedure Calls 3-3
1. 2. 3. 4. 5. 6. The NM code needing to access a CM routine calls Switch, either by means of in-line code or a Switch stub. The in-line code or NM Switch stub sets up the data structures and parameters required by Switch and makes a call to the HPSWITCHTOCM intrinsic (call by name), or the HPLOADCMPROCEDURE and HPSWITCHTOCM intrinsics (call by plabel).
Switch to CM Details Switch requires the following information to call a CM procedure from an NM procedure: Name of the CM SL routine and the library containing it or the 16-bit CM plabel of a currently loaded copy of the routine Number of parameters in the calling sequence of the CM SL routine Length of each actual parameter For each parameter, a designation as an input parameter, an output parameter, or both For each parameter, an indication whether the CM SL routine expects that parameter to be a value
HPSWITCH TOCM Intrinsic The mechanism that enables mixed-mode calls in the NM|> CM direction is the HPSWITCHTOCM intrinsic.
Caution HPSWITCHTOCM does no checking for overlapping reference parameters. On MPE V/E-based systems, you may have used overlapping reference parameters to obtain side e ects since both copies could share the overlap area. In Native Mode, the parameters will overlap. In Compatibility Mode, however, the parameters will be placed one on top of the other on the CM stack. If you rely on this particular e ect, the results will not be as expected.
The syntax of the HPSWITCHTOCM intrinsic and detailed explanations of its parameters are given in the following paragraphs. Also provided are examples of switches in the NM|> CM direction. Syntax Prior to calling the HPSWITCHTOCM intrinsic, your programming language may require you to declare it.
Note If the SPL procedure is option variable (see the MPE V/E Intrinsics Reference Manual (32033-90007) or the header of a non-intrinsic SPL procedure), you must construct the option variable mask and pass it as the last parameter. See Example 3-11 for an illustration. All this information is key to the correct interpretation of data, return values, and status information when you make mixed-mode procedure calls.
Parameters A detailed explanation of the parameters of the HPSWITCHTOCM intrinsic follows. Required parameters are shown in boldface; optional parameters are shown in italics . proc record (required) Passes the target CM procedure identi er, which you can specify either by a library to search and an ASCII name of up to 16 characters or by a CM plabel (obtained from the HPLOADCMPROCEDURE or LOADPROC intrinsic). The structure of the proc record varies, depending on how the target procedure is identi ed.
{proc found by plabel} pidt_plabel : ( {proc's CM plabel} p_plabel : bit16_a1); end; NM-to-CM Procedure Calls 3-11
If you designate the target CM procedure by means of an ASCII name, then the following apply: The value of the p proc id type eld is 1. The search library is designated in a p lib eld whose value can be 0 for the system SL, 1 for the logon pub SL, 2 for the logon group SL, 3 for the program's pub SL, or 4 for the program's group SL. The ASCII name is designated in the p proc name eld and can be up to 15 bytes long. The name is padded on the right with blanks to a length of 16 bytes.
perform any hashing and, consequently, involves high system overhead every time it is called.
If you designate the target CM procedure by means of a plabel, then the following apply: The value of the p proc id type eld is 2. A p plabel eld designates the plabel.
method 32-bit signed integer by value (required) Value indicating whether the CM target procedure runs in normal, split-stack, or no copy mode. The valid values and their meanings follow: 0 Normal (non-split-stack) Method 1 Split-stack Method 2 No-copy Method Note The split-stack method works as follows: If all parameters are within the CM stack, or the length of the reference parameters is less than the threshold, then use normal method.
being described.
pd parm type 16-bit unsigned integer Provides information needed to determine the kind of mapping to be performed during the transfer of the parameter. The allowed mappings are as follows: 0 Value parameter 1 Reference parameter requiring word address 2 Reference parameter requiring byte address pd io type 32-bit signed integer Applies only to reference parameters and speci es whether such a parameter is input, output, or both.
Note The pd parmptr eld is a 64-bit address that is currently supported only in HP Pascal/XL. Table 3-1 summarizes, according to MPE XL-supported language, the data alignments of the common data types.
Table 3-1.
fretlen 32-bit signed integer by value (optional) The length in bytes of the optional functional return value. The default is 0. record (optional) fretval A single-element record containing a 32-bit NM pointer to the beginning of the area to which the optional functional return value is returned. The HP Pascal/XL declaration of this record is as follows: LOCALANYPTRREC = RECORD (rtn_addr: LOCALANYPTR); END; condcode The default value of this pointer is nil.
Bits (0:16) comprise status.info . A negative value indicates an error condition, and a positive value indicates a warning condition. Bits (16:16) comprise status.subsys . The value represented by these bits de nes the subsystem that set the status information. The Switch identi cation number is 100. The values of status.info that can be returned from a call to HPSWITCHTOCM are listed in ***: undefined***.
Table 3-2. HPSWITCHTOCM Status Returns (Page 1) Status Code 3-22 Meaning -20 Invalid method parameter value (not in range 0 . . .
Table 3-2.
Caution Since HPSWITCHTOCM can return information on the success of its execution in the status parameter, it is good programming practice to specify this parameter and check its value after the intrinsic call. If an error or warning condition is encountered and you did not specify the status parameter, HPSWITCHTOCM causes the calling process to abort. HPSWITCHTOCM makes the following checks on its parameters: If a plabel is used, it is range-checked.
HPLOADCM PROCEDURE Intrinsic Switching by name incurs the overhead of forming a hash probe out of the procedure's name and nding the name in a hash table in order to obtain the procedure's plabel. You can eliminate this overhead by obtaining the target procedure's plabel through the Switch support intrinsic function HPLOADCMPROCEDURE. You then supply the result returned by HPLOADCMPROCEDURE as the value of the proc parameter in the call to the HPSWITCHTOCM intrinsic.
Parameters A detailed explanation of the parameters of the HPLOADCMPROCEDURE intrinsic follows. Required parameters are shown in boldface; optional parameters are shown in italics . proc character array (required) lib Passes an ASCII procedure name, left-justi ed and blank-padded. The name can have a maximum of 15 characters. The name is padded with blanks to a length of 16. 8-bit unsigned integer (optional) Passes indicator of the CM SL to be searched.
status status-record (optional) Returns the status of the intrinsic call. If no errors or warnings are encountered, status returns 32 bits of zero. If errors or warnings are encountered, status is interpreted as two 16-bit elds. The HP Pascal/XL declaration of this record is as follows: XLSTATUS CASE 0 1 = RECORD INTEGER OF : (all : INTEGER); : (info : SHORTINT; subsys : SHORTINT); END; {record} Bits (0:16) comprise status.info .
Table 3-3. CM Loader Status Returns (Page 1) Status Code 3-28 Meaning -1020 Illegal library search. -1021 Unknown entry point. -1022 The TRACE subsystem is not present. -1023 The stack size is too small. -1024 Maxdata is greater than 32K. -1025 The data segment is greater than the maxdata segment. -1026 The program is loaded in the opposite mode. -1027 SL binding error. -1028 Invalid system SL le. -1029 Invalid public SL le. -1030 Invalid group SL le. -1031 Invalid program le.
Table 3-3. CM Loader Status Returns (Page 2) Status Code Meaning -1043 Illegal procedure unload. -1044 Illegal SL capability. -1045 Invalid entry point. -1050 Unable to open system SL le. -1051 Unable to open public SL le. -1052 Unable to open group SL le. -1053 Unable to open program le. -1054 Unable to open list le. -1055 Unable to close system SL le. -1056 Unable to close public SL le. -1057 Unable to close group SL le. -1058 Unable to close program le.
Table 3-3. CM Loader Status Returns (Page 3) Status Code 3-30 Meaning -1070 Segment Table over ow. -1071 Unable to obtain su cient DL storage. -1072 ATTIO error. -1073 Unable to obtain virtual memory. -1074 Directory I/O error. -1075 Print I/O error. -1076 Illegal DLSIZE. -1080 The program is already allocated. -1081 Illegal program allocation. -1082 The program is not allocated. -1083 Illegal program deallocation. -1084 The procedure is already allocated.
Table 3-4. Table 3-3. CM Loader Status Returns (Page 4) Status Code Meaning -1100 There are too many mapped segments. -1101 The SEGMAP is too big. -1102 Unable to expand SEGMAP. -1103 There are too many dynamic loads on the procedure.
HPUNLOADCM PROCEDURE Intrinsic Procedures whose plabels are obtained via the HPLOADCMPROCEDURE intrinsic function are automatically unloaded when the process terminates. However, you can use the HPUNLOADCMPROCEDURE intrinsic to do the unloading before the process terminates.
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.
Figure F03-02 here. 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.
The following sample procedure declarations demonstrate these aspects of achieving mixed-mode calling transparency.
+---------+ +-| 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: +--------+
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.
Example 3-1A.
{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.
parm_type_value = parm_type_word_ref = parm_type_byte_ref = 0; {value parameter } 1; {word address is required} 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 =
ccg = ccl = cce = 0; 1; 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..
var proc : parms : method : nparms : scm_procedure; {target proc name} scm_parm_desc_array; {describes target proc's parameters} integer; {method of call} integer; {# of target's parameters} Example 3-1A.
proc.p_proc_id_type := pidt_load; {find proc by name} proc.p_lib := pub_sl; {look in PUB SL (LIB=P)} proc.
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].
{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].
{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].
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 ts into the ow of control and enables you to access your CM SL CONVERTDATE procedure: Figure F03-03 here. Figure 3-3. NM| > CM Switch Summary 2 Example 3-2 implements a Switch stub for the BINARY intrinsic.
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. Note Example 3-2.
Cce All_ok = 2; {condition code equal (=)} = 0; {used in status check} TYPE BIT8 BIT16 BIT8_A1 BIT16_A1 CM_PROC_NAME GENERIC_BUFFER = = = = = = 0..255; 0..65535; $ALIGNMENT 1$ BIT8; $ALIGNMENT 1$ BIT16; PACKED ARRAY [1..16] of CHAR; PACKED ARRAY [1..65535] of CHAR; Example 3-2.
SCM_PARM_DESC_ARRAY = ARRAY [0..
Example 3-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.
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 parms[0].pd_parmlen parms[0].pd_parm_type parms[0].pd_io_type := := := := ADDR(F1); byte_len_of_parm; Parm_Type_Byte_Ref; [Input_Parm]; {F2 -- Input Only by Value } byte_len_of_parm := 2; parms[1].pd_parmptr parms[1].pd_parmlen parms[1].pd_parm_type parms[1].
END {Switch subsystem error} else binary := funcval; HPSETCCODE(cond_code); END; {STUB procedure} BEGIN {Program Outer Block code} END.
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-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.
<< 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.
Example 3-4.
{end Example 3-4} NM-to-CM Procedure Calls 3-59
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; NO. ERRORS=0000; PROCESSOR TIME=0:00:00; SECONDARY DB STORAGE=%00000 NO.
SL FILE SL.DTJ.DTEST SEGMENT 2 EXAMPLE LENGTH 204 ENTRY POINTS D2A D'EXP CHECK CAL STT ADR 0 C 1 0 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.
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.
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.
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.
Cce All_ok = 2; {condition code equal (=)} = 0; {used in status check} NM-to-CM Procedure Calls 3-65
Example 3-8. HP Pascal/XL Program With Inline Switch, continued TYPE BIT8 BIT16 BIT8_A1 BIT16_A1 CM_PROC_NAME GENERIC_BUFFER SHORTINT = = = = = = = 0..255; 0..65535; $ALIGNMENT 1$ BIT8; $ALIGNMENT 1$ BIT16; PACKED ARRAY [1..16] of CHAR; PACKED ARRAY [1..65535] of CHAR; -32768..
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 count status parms proc_info i : : : : : : shortint; shortint; xlstatus; scm_parm_desc_array; scm_procedure; integer; Example 3-8.
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; status.
path. In Example 3-8, this sort of test is intentionally omitted. Instead, the routine prints out the values of the status parameter elds. Example 3-9.
Ccg Ccl Cce All_ok = = = = 0; 1; 2; 0; {condition code {condition code {condition code {used in status greater (>)} less (<)} equal (=)} check} Example 3-9. HP Pascal/XL Switch Stub, continued TYPE BIT8 BIT16 BIT8_A1 BIT16_A1 CM_PROC_NAME GENERIC_BUFFER = = = = = = 0..255; 0..65535; $ALIGNMENT 1$ BIT8; $ALIGNMENT 1$ BIT16; PACKED ARRAY [1..16] of CHAR; PACKED ARRAY [1..
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 hp_integer hp_real hp_long hp_char = = = = = $alignment $alignment $alignment $alignment $alignment 2$ 2$ 2$ 2$ 1$ shortint; integer; real; longreal; char; Example 3-9.
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.
{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].
end.
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.
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 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).
Special Considerations and Restrictions There are certain considerations to bear in mind when you use Switch. General General considerations apply no matter what the direction of the mixed-mode call: Mixed-mode procedure calls require an increased level of programming complexity. The overhead of Switch can be signi cant. Because Switch does no probing on addresses passed by the caller, data memory protection faults are likely when you pass in bad parameter addresses or lengths.
NM| > CM When making mixed-mode procedure calls in the direction NM|> CM, the following considerations apply: Any CM procedure called from NM code must reside in a CM SL. The SL containing the procedure must be accessible via the LOADPROC or HPLOADCMPROCEDURE intrinsic. This may be the system library, a group library, or a user library. Unlike other MPE XL intrinsics, the Switch intrinsics do not promote their privilege level.
Example 3-11.
BIT16_A1 CM_PROC_NAME GENERIC_BUFFER = $ALIGNMENT 1$ BIT16; = PACKED ARRAY [1..16] OF CHAR; = 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 } Example 3-11.
PROCEDURE HPSETCCODE; INTRINSIC; PROCEDURE QUIT; INTRINSIC; { End of OUTER BLOCK GLOBAL declarations } PROCEDURE FCHECK $ALIAS 'FCHECK'$ ( FILENUM : SHORTINT; VAR ERRORCODE : SHORTINT; VAR TLOG : SHORTINT; VAR BLKNUM : INTEGER; VAR NUMRECS : SHORTINT ); VAR proc parms method nparms funclen funcptr byte_len_of_parm cond_code status mask : : : : : : : : : : SCM_PROCEDURE; SCM_PARM_DESC_ARRAY; INTEGER; INTEGER; INTEGER; INTEGER; BIT16; CCODE_TYPE; XLSTATUS; BIT16; Example 3-11 Stub for Option Variable Targe
proc.p_proc_id_type := proc.p_lib := proc.p_proc_name := Pidt_Name; { By name } System_Sl; { Library } 'FCHECK '; { Setup misc. variables } mask method nparms := := := 0; Method_Normal; 6; { Split stack? } { 5 + mask } { Setup length/pointers for functional return if this } { is a FUNCTION. Set length to zero, pointer to NIL } { if this is not a FUNCTION.
byte_len_of_parm := 2; mask := ior16(mask, binary('01000')); parms[1].pd_parmptr := ADDR(ERRORCODE); parms[1].pd_parmlen := byte_len_of_parm; parms[1].pd_parm_type := Parm_Type_Word_Ref; parms[1].pd_io_type := [Output_Parm]; Example 3-11. Stub for Option Variable Target Procedure, continued { TLOG -- Output Only by REFERENCE } byte_len_of_parm := 2; mask := ior16(mask, binary('00100')); parms[2].pd_parmptr := ADDR(TLOG); parms[2].pd_parmlen := byte_len_of_parm; parms[2].
{ mask parameter } parms[5].pd_parmptr := ADDR(mask); parms[5].pd_parmlen := byte_len_of_parm; parms[5].pd_parm_type := parm_type_value; parms[5].pd_io_type := [Input_Parm]; { Do the actual SWITCH call } HPSWITCHTOCM(proc, method, nparms, parms, funclen, funcptr, cond_code, status); { { { { { { { { Procedure info Split stack ? Number of parameters Parm descriptor array func ret value length Addr of func return cond. code return SWITCH status code } } } } } } } } if (status.
Testing and Debugging Considerations You must test Switch stubs and inline Switches in the run-time environment on an MPE XL-based system. You must either compile the stub and install the compiled version in the appropriate system library or merge it with the code requiring the Switch call and recompile that merged source. You can also compile the stub and then link it with the USL/SOM le for the program that calls it.
4 CM-to-NM Procedure Calls This section presents the following topics: Review of the ow of control in CM|> NM switches Details of CM|> NM switches, including their inner workings, syntax, parameters, and examples Special considerations and restrictions that apply to mixed-mode procedure calls Testing and debugging considerations This chapter provides the detailed reference information you will need if you write your own CM-to-NM Switch stubs.
Flow of Control: CM| > NM The ow of control for mixed-mode procedure calls in the direction CM|> NM is illustrated in Figure 4-1: Figure 4-1.
1 2 3 4 5 6 The CM code needing to access an NM routine calls Switch, either by means of in-line code or a Switch stub. The in-line code or CM Switch stub sets up the data structures and parameters required by Switch and makes a call to either the HPSWTONMNAME intrinsic or the HPLOADNMPROC and HPSWTONMPLABEL intrinsics. HPSWTONMNAME or HPSWTONMPLABEL calls the NM routine, after preparing the NM registers as though the call was being made from Native Mode.
Switch to NM Details Switch requires the following information to call an NM procedure from a CM procedure: Name of the procedure or an NM plabel (32-bits) If the NM procedure is speci ed by name, the following additional items are required: Length of the procedure name NM library to search for the target procedure Length of the library name Number of parameters being passed to the NM procedure Array of values and/or pointers to the parameters being passed Array of descriptions of the parameters being pass
Note The rst time a switch by name occurs in either direction, a load from the library occurs. Thereafter, Switch uses an internal hash table to quickly invoke the already loaded procedure.
HPSWTONM NAME Intrinsic The HPSWTONMNAME intrinsic allows CM user programs, user libraries, and system code to invoke NM procedures. In a manner similar to the HPSWITCHTOCM intrinsic, HPSWTONMNAME does the following: Converts the CM references in the argument list to virtual NM addresses Changes the execution mode Invokes the NM procedure speci ed by the CM caller Since NM code can address the entire CM stack, there is no copying of reference parameters.
Syntax Prior to calling the HPSWTONMNAME intrinsic, your programming language may require you to declare it. In Pascal/V, the declaration is as follows: FUNCTION HPSWTONMNAME : INTEGER; INTRINSIC; Next comes an example of a Pascal/V call to this intrinsic: return_status := HPSWTONMNAME (procname, proclen, libname, liblen, nparms, arglist, argdesc, functype); You call the HPSWTONMNAME intrinsic with eight parameters.
Parameters A detailed explanation of the parameters of the HPSWTONMNAME intrinsics follows. Required parameters are shown in boldface; optional parameters are shown in italics . procname byte array by reference (required) Passes the target procedure name. The target procedure must be contained in an Executable Library (XL). If the value of procname is invalid, blank, or does not contain your NM procedure, NL.PUB.SYS is searched.
Passes integer codes describing the parameters held in the arglist array. Refer to Tables 4-2, 4-3, and 4-4. functype 16-bit signed integer by value (required) Passes the data type of the value the target procedure returns if it is a function. If the target is not a function, the value of this parameter is zero. The supported function types are described in Table 4-5.
Note It is your responsibility to build and load the argument arrays and make the call to Switch. The arglist array is an image of the target procedure's argument list as it would appear in the stack if the routine were in Compatibility Mode. Space for the function return value (if any) comes rst, followed in order by the rst through last parameters. Value parameters are represented by their values, and reference parameters are represented by their DB-relative addresses.
passed by value. The descriptor types map to parameters, not to arglist elements.
Figure 4-2 illustrates the relationship between the argdesc and arglist arrays: Figure 4-2.
The descriptors in the argdesc array are intergers that represent the type of the associated parameter. The type IDs and their NM and CM sizes (in bits) are listed in Table 4-1. The types and their associated SPL-HP Pascal/XL, Pascal/V-HP Pascal/XL, and COBOL II/V-HP Pascal/XL mappings are listed in Tables 4-2, 4-3, and 4-4, respectively. Types 1 through 4 direct Switch to pass by value the corresponding parameters you have placed in arglist Types 5 and 6 are used to pass reference parameters only.
Table 4-1.
Table 4-2. SPL| > HP Pascal/XL Parameter Type Mappings If the NM procedure you are Declare it like this in switching to has a And do the following to pass the Pascal/V variable Pascal/V: parameter declared as through the follows: switch: TYPE bit8 = 0..
When calling Switch from Pascal/V, declare two arrays as follows: TYPE shortint = -32768..32767; VAR argdesc : array [1..32] of shortint; arglist : array [1..64] of shortint; Then, for each parameter, follow the appropriate instructions given in Table 4-3.
Pascal/V| > Table 4-3. HP Pascal/XL Parameter Type Mappings (Page 1) If the NM procedure you are Declare it like this in switching to has a SPL: And do the following to pass the SPL variable through parameter declared as the follows: switch: TYPE bit8 = 0..255; TYPE bit8 = 0..255; argdesc[n] := 1; arglist[n] := A; A : bit8; A : bit8; B : shortint; B : shortint; C : integer; argdesc[n] := 3; TYPE split_word = arglist[n] := C.hi; record arglist[n+1] := C.
TABLE 4.3 Ppascal/V| > HP Pascal/XL Parameter Type Mappings (Page 2) If the NM procedure you are Declare it like this in switching to has a SPL: And do the following to pass the SPL variable through the parameter declared as follows: switch: TYPE 16_bit_ary = array [1..N] of shortint; TYPE 32_bit_ary = array [1..N] of integer; TYPE 16_bit_ary = array [1..N] of shortint; TYPE 32_bit_ary = array [1..
Then, for each parameter, follow the appropriate instructions given in Table 4-4.
> COBOL II/V - Table 4-4. HP Pascal/XL Parameter Type Mappings(Page 1) If the NM procedure you are Declare it like this in switching to has a COBOL II/V: And do the following to pass the COBOL II/V variable through the parameter declared as follows: switch: TYPE bit8 = 0..255; A : bit8; 01 A PIC X. or 01 A PIC 9. or 01 A PIC 9 COMP. B : shortint; 01 01 01 01 C : integer; 01 C PIC S9(5) COMP. MOVE C-HI TO ARGLIST(N). 01 C PIC S9(6) COMP. MOVE C-LO TO 01 C PIC S9(7) COMP. ARGLIST(N+1).
> Table 4-4. COBOL II/V - HP Pascal/XL Parameter Type Mappings(Page 2) If the NM procedure you are Declare it like this in And do the following to pass switching to has a parameter COBOL II/V: the COBOL II/V variable declared as follows: through the switch: Reserved for MPE XL. Do not use. Do not use. Reserved for MPE XL. Do not use. Do not use. Reserved for MPE XL. Do not use. Do not use. VAR J : anyptr; 01 J PIC X(80) OCCURS N TIMES. CALL ".LOC." USING J GIVING ARGLIST(N).
d TYPE SPL Function ID Type 0 1 2 3 4 CM Size (Bytes) Pascal/XL Function Type (0) (1) (2) (4) (8) not a function bit8 shortint integer longreal none byte integer double long NM Size (Bytes) (0) (1) (2) (4) (8) c b Figure 4-3. Supported Function Type Mappings Note A function return value is placed in the rightmost 8 bits of the rst element of the arglist array. The leftmost 8 bits of arglist(1) is used if the NM procedure you are switching to has a parameter declared as follows: TYPE bit8 = 0..
HPSWTONM PLABEL Intrinsic The HPSWTONMPLABEL intrinsic allows CM user programs, user libraries, and system code to invoke NM procedures. In a manner similar to the HPSWITCHTOCM intrinsic, HPSWTONMPLABEL does the following: Converts the CM references in the argument list to virtual NM addresses Changes the execution mode Invokes the NM procedure speci ed by the CM caller Since NM code can address the entire CM stack, there is no copying of reference parameters.
Syntax Prior to calling the HPSWTONMPLABEL intrinsic, your programming language may require you to declare it. In Pascal/V, the declaration is as follows: FUNCTION HPSWTONMPLABEL : INTEGER; INTRINSIC; Next, an example Pascal/V call to this intrinsic: return_status := HPSWTONMPLABEL (proc, nparms, arglist, argdesc, functype); You call the HPSWTONMPLABEL intrinsic with ve parameters.
Parameters A detailed explanation of the parameters of the HPSWTONMPLABEL intrinsic follows. Required parameters are shown in boldface; optional parameters are shown in italics . proc double by value (required) Passes the NM plabel of the target procedure name. This plabel is usually obtained by calling the HPLOADNMPROC intrinsic. nparms 16-bit signed integer by value (required) Passes the number of parameters you are passing to the target NM procedure. It speci es the length of the argdesc array.
HPLOADNM PROC Intrinsic The HPLOADNMPROC intrinsic returns the plabel of an NM procedure. You call this intrinsic to obtain the NM plabel of the target procedure. This plabel is then used by the HPSWTONMPLABEL intrinsic as the value of its proc parameter. Syntax Prior to calling HPLOADNMPROC , your programming language may require you to declare it.
Parameters A detailed explanation of the parameters of the HPLOADNMPROC intrinsic follows. Required parameters are shown in boldface; optional parameters are shown in italics . procname byte array by reference (required) Passes the target procedure name. The target procedure must be contained in an Executable Library. If the value of procname is invalid, blank, or does not contain your NM procedure, NL.PUB.SYS is searched.
Examples: CM to NM and Return Now consider an example of the mixed-mode switching process in the CM| > NM direction. The HPCIDELETEVAR intrinsic removes an entry from the session-local variable table. This intrinsic is not directly callable from Compatibility Mode. However, you can call it from CM code by means of a CM|> NM Switch stub. The syntax of the HPCIDELETEVAR intrinsic is as follows: CA I32 HPCIDELETEVAR(varname, status); The varname parameter is a required character array.
Figure 4-4 illustrates the purpose of the CMDeleteVar Switch stub. Figure F04-03 here. Figure 4-4. HPSWTONMNAME Example, CMDeleteVar The Switch stub sets up the parameters required by the appropriate Switch intrinsic. In this instance, that is the HPSWTONMNAME intrinsic.
The parameters that the CMDeleteVar Switch stub must set up before it can call the HPSWTONMNAME intrinsic convey to Switch the following information: Name of the NM routine Length of the procedure name NM library to search for the target procedure Length of the library name Number of parameters of the NM routine Parameter list Parameter description list Type of the functional return value (if any) Example 4-1 contains the complete Switch to NM stub.
Example 4-1. CMDeleteVar Stub { XAMPL41 -- Switch to NM by name } $standard_level 'HP3000'$ {$subprogram$} {uncomment this to make an RBM for your SL} $uslinit$ PROGRAM XAMPL41(input, output); {Type Declarations} TYPE shortint = -32768..32767; shr_ary32 = packed array [1..32] of shortint; xlstatus = record case integer of 0 : (all : integer); 1 : (info : shortint; subsys : shortint); end; pac16 = packed array [1..16] of char; pac255 = packed array [1..
FUNCTION HPLOADNMPROC : integer; intrinsic; 4-32 CM-to-NM Procedure Calls
Example 4-1.
arglist[1] := 0; arglist[2] := 0; {extensible gateway mask is 32 bits} {of anything, all 0 bits works ok! } arglist[3] := baddress(CIVarName); {reference parameter passed by address; } {take byte address of variable name buffer} arglist[4] := waddress(NMStatus); {reference parameter passed by address;} {take word address of local status} 4-34 CM-to-NM Procedure Calls
Example 4-1. CMDeleteVar Stub, continued argdesc[1] := 03; {32-bit word value for gateway mask} argdesc[2] := 05; {byte pointer for arglist[3]} argdesc[3] := 06; {word pointer for arglist[4]} fct_typ := 00; {This is an NM procedure, not a {function. If it was an NM function, the {return value would come back in {arglist[1..n] where n is the length of {the value in 16-bit words.
VarName := 'DELETE_ME'; status.all := 0; CMDeleteVar(VarName, status); writeln('Status for subsystem ', status.subsys:3); writeln(' is ', status.info:3); END.
Note For a complete analysis of CM|> NM Switch stub code, refer to Chapter 5. Figure 4-5 illustrates how your CMDeleteVar Switch stub accesses the HPCIDELETEVAR intrinsic in NL.PUB.SYS. Figure F04-04 here. Figure 4-5.
Example 4-2 illustrates a CM|> NM Switch, using a COBOL II/V stub procedure in Compatibility Mode to access an HP Pascal/XL target procedure in Native Mode. Both the stub and the target are included in Example 4-2. > NM Switch, COBOL Example 4-2. CM| { XAMPL42 -- example Switch to $CONTROL USLINIT IDENTIFICATION DIVISION. PROGRAM-ID. XAMPL42. ENVIRONMENT DIVISION. CONFIGURATION SECTION. DATA DIVISION. WORKING-STORAGE SECTION.
* MOVE 1 TO ADD-TO-PARM. > NM Switch, COBOL, continued Example 4-2. CM| * * ESTABLISH PROCNAME, LIBNAME, AND ASSOCIATED LENGTHS. * MOVE MOVE MOVE MOVE MOVE "testadd" TO PROCNAME. 7 TO PROCNAME-LEN. "NL" TO LIBNAME. 2 TO LIBNAME-LEN. 2 TO NPARMS. * * BUILD THE ARGUMENT LIST ARRAY: * 1) 0 RESERVES SPACE FOR THE RETURN VALUE * 2) 99 RESERVES SPACE FOR THE FIRST PARAMETER (BY VALUE), * CALL .LOC. INTRINSIC TO GET ADDRESS OF THE * BY-REFERENCE PARAMETER * MOVE 0 TO LIST-ELEMENT( 1 ).
CALL "HPSWTONMNAME" USING @PROCNAME, \PROCNAME-LEN\, @LIBNAME, \LIBNAME-LEN\, \NPARMS\, ARGLIST, ARGDESC, \2\ GIVING SWITCH-STATUS. * * TEST STATUS * IF SWITCH-STATUS IS NOT ZERO MOVE SWITCH-INFO TO DISP-INFO MOVE SWITCH-SUBSYS TO DISP-SUBSYS DISPLAY "Status info = ", DISP-INFO DISPLAY "Status subsys = ", DISP-SUBSYS ELSE DISPLAY "HPSWTONMNAME completed successfully". > NM Switch, COBOL, continued Example 4-2. CM| * * SHOW THE RETURN VALUE (WHICH SHOULD BE 100) * MOVE LIST-ELEMENT( 1 ) TO DISP-ANSWER.
program dummy_outer_block(input, output); TYPE A8_INTEGER = $ALIGNMENT 1$ INTEGER; FUNCTION TESTADD( byvalueparm : SHORTINT; VAR byrefparm : A8_INTEGER ) : SHORTINT; BEGIN {function testadd } TESTADD := byvalueparm + byrefparm; END; {function testadd } BEGIN {dummy_outer_block } END.
Switch to NM Sequence Examples 4-3 through 4-8 are a series of routines, intended to illustrate the partial recompilation migration level, using a CM|> NM switch. In these examples the target procedure migrates to Native Mode while the calling routine remains in Compatibility Mode.
A possible reason for moving the target procedure to Native Mode is that it has a feature that is no longer available on MPE XL and an attractive alternative exists in the NM environment. Example 4-3 is a Pascal/V source with a procedure call to the PTAPE intrinsic (deleted on MPE XL). Example 4-3. Pascal/V Program Calling Routine With Deleted Featur PROGRAM XAMPL43(input,output); TYPE pac37 = packed array [1..37] of char; logical = 0..65535; shortint = -32768..
writeln('fopen ',fname,'ccode is ',ccode); fname2 := 'XMPLA '; foptions2 := 0; aoptions2 := 0; recsize2 := 0; dev2 :=0; filenum2 := FOPEN(fname2, foptions2, aoptions2, recsize2, dev2); writeln('fopen ',fname2,'ccode is ',ccode); 4-44 CM-to-NM Procedure Calls
Example 4-3. Pascal/V Program, continued PTAPE(filenum1,filenum2); writeln('ptape result: '); case ccode of 0 : writeln('CCE'); 1 : writeln('CCG'); 2 : writeln('CCL'); end; END. {end Example 4-3} Example 4-4 is an SPL procedure incorporating the call to the PTAPE intrinsic. Example 4-4.
END UNTIL <>; END; END.
To replace the deleted feature, you may want to write your own NM procedure. Example 4-5 is an HP Pascal/XL procedure replacing the call to the deleted PTAPE intrinsic with an MPE XL feature. This procedure will replace the SPL procedure. Example 4-5. Pascal/XL Procedure Replacing Deleted Feature $standard_level 'ext_modcal'$ $subprogram$ PROGRAM XAMPL45 (input,output); TYPE pac256 = packed array [1..
begin end.
It is advisable to test one thing at a time. You can test the NM replacement procedure separately from a Switch stub or in-line Switch that calls the appropriate intrinsic to invoke the target. Example 4-6 is an NM driver to test the HP Pascal/XL procedure. Example 4-6. NM Driver $standard_level 'ext_modcal'$ PROGRAM XAMPL46(input,output); TYPE pac37 logical VAR fname1 fname2 filenum1 filenum2 foptions1 foptions2 aoptions1 aoptions2 recsize1 recsize2 dev1 dev2 = packed array [1..37] of char; = 0..
filenum1 := FOPEN(fname1, foptions1, aoptions1, recsize1, dev1); writeln('fopen ',fname1,'ccode is ',ccode); fname2 := 'PTAPE '; foptions2 := 0; aoptions2 := 0; recsize2 := 0; dev2 := 0; filenum2 := FOPEN(fname2, foptions2, aoptions2, recsize2, dev2); writeln('fopen ',fname2,'ccode is ',ccode); 4-50 CM-to-NM Procedure Calls
Example 4-6. NM Driver, continued ptape(filenum1,filenum2); writeln('ptape result: '); case ccode of 0 : writeln('CCE'); 1 : writeln('CCG'); 2 : writeln('CCL'); end; END. {end Example 4-6} As it stands, the HP Pascal/XL procedure represents an unresolvable external reference to the CM routine that must call it. Again, you can use either a Switch stub or an in-line Switch to enable the CM caller to access the NM target. Example 4-7 is a Pascal/V Switch stub enabling access to the HP Pascal/XL procedure.
lib_name lib_len nparms arglist argdesc fct_type rtn_st 4-52 : : : : : : : pac16; shortint; shortint; shr_ary32; shr_ary32; shortint; integer; CM-to-NM Procedure Calls
Example 4-7. Pascal/V Switch Stub, continued BEGIN proc_name proc_len lib_name lib_len nparms := := := := 'PTAPE 5; 'SL 2; '; '; := 2; arglist[1] := file1; arglist[2] := file2; argdesc[1] := 02; argdesc[2] := 02; fct_type := 0; { 16-bit value } { 16-bit value } {not a function } rtn_st := HPSWTONMNAME(proc_name, proc_len, lib_name, lib_len, nparms, arglist, argdesc, fct_type); END; BEGIN END. {end Example 4-7} To compile the Switch stub in Example 4-7, use the :PASCAL command.
Example 4-8. Segmenter Session :SEGMENTER HP32050A.02.00 SEGMENTER/3000 (C) HEWLETT-PACKARD CO 1985 -SL SL -LISTSL SL FILE SL.SWITCH.EXAMPLE SEGMENT 0 SWCMLIB LENGTH ENTRY POINTS PTAPE CHECK CAL STT ADR 3 C 1 13 EXTERNALS FWRITE FREAD CHECK STT SEG 0 13 ? 0 12 ? USED 4600(23.0) AVAILABLE 2334200(11565.
Special Considerations and Restrictions There are certain considerations to bear in mind when you use Switch. General General considerations apply no matter what the direction of the mixed-mode call: Mixed-mode procedure calls require an increased level of programming complexity. The overhead of Switch can be signi cant. Since Switch does no parameter type or alignment checking, the target procedure must make the necessary checks.
Testing and Debugging Considerations You must test Switch stubs and inline Switches in the run-time environment on an MPE XL-based system. You must either compile the stub and install the compiled version in the appropriate system library or merge it with the code requiring the Switch call and recompile that merged source. You can also compile the stub and then link it with the USL/SOM le for the program that calls it.
5 Writing Switch Stubs You will nd the information in this and the following chapter of value if you fall into one of these categories: You must modify the stubs generated by the Switch Assist Tool because of the special nature of your application (see \Special Cases" in Chapter 2). You choose to write your own Switch stubs. You are the inquisitive type whose curiosity compels you to take things apart and nd out how they work.
Switching to CM To illustrate a mixed-mode switch to Compatibility Mode (CM), consider the example of an SPL procedure DECMADD that adds two packed decimal numbers, OPERAND1 and OPERAND2, and leaves a packed decimal result in RESULT. DECMADD also has a parameter DIGITS that contains the total number of whole digits in each parameter and a parameter FRAC that contains the total number of fractional digits in each parameter.
Writing the DECMADD Stub Declarations Begin the process of writing a Switch stub with the declaration portion of the procedure. To guarantee that the switching process is transparent to the calling program, follow these guidelines: Make the stub name identical to that of the SPL procedure. Make the types of the stub parameters correspond to those of the SPL procedure. Type correspondence refers both to status as either value or reference parameter, as well as to the data type of the parameter.
+---------------------------------------------------------+ Note 5-4 The data type shortint is used to correspond to the SPL INTEGER type because DECMADD is a CM routine and integers in Compatibility Mode are 16-bit.
Declaring the Stub Parameters The next step in writing a Switch stub is to set up the parameters required by the particular Switch intrinsic, in this instance HPSWITCHTOCM . Consider again the declaration of the HPSWITCHTOCM intrinsic: PROCEDURE HPSWITCHTOCM; INTRINSIC; Next comes an example of an HP Pascal/XL call to HPSWITCHTOCM: HPSWITCHTOCM(proc, method, numparms, parms, funcreturnlen, funcvalue, conditioncode, userstatus); You call the HPSWITCHTOCM intrinsic with eight parameters.
Setting up these parameters involves three stages: 1. Declaring the necessary constants 2. Declaring the necessary user-de ned types 3. Declaring the necessary variables Declaring Constants.
Example 5-1. DECMADD Stub, Constant Declarations const {The OS finds procedure either by number, by name, or {by plabel.
Several user-declared types are necessary to set up the stub procedure variables.
Example 5-2. DECMADD Stub, Type Declarations type bit8 bit16 bit8_a1 bit16_a1 = = = = 0..255; 0..65535; $ALIGNMENT 1$ bit8; $ALIGNMENT 1$ bit16; {type declaration for procedure names} cm_proc_name = packed array [1..16] of char; {defining generic buffer type} generic_buffer = packed array [1..
{define 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; pd_parmlen : bit16; pd_parm_type : bit16; pd_io_type : scm_io_type; end; {where parameter found} {size in bytes } {byte or word address } {input and/or output } {defining type of HPSWITCHTOCM parms parameter} scm_parm_desc_array = array [0..31] of parm_desc; Example 5-2.
The variable declaration section for the DECMADD stub follows in Example 5-3: Example 5-3.
{declaring the QUIT intrinsic} PROCEDURE QUIT; INTRINSIC; {end Example 5-4} Writing the DECMADD Stub Body Once the declaration section is complete, it is possible to proceed to the body of the Switch stub procedure. In the body, the actual work of setting up the parameters required by the HPSWITCHTOCM intrinsic is done.
begin {initializing local variables} loc_digits :=-----------; {initialize local copy of DIGITS} loc_frac :=-----------; {initialize local copy of FRAC } {initializing SWITCH variables} proc.p_proc_id_type proc.p_lib := proc.
{determine length of parameter; sizeof function takes } {parameter as argument and returns number of bytes } parms[0].pd_parmlen := sizeof(--------------------); {reference parameter requiring byte address} parms[0].pd_parm_type := -----------------------------; {input parameter} parms[0].pd_io_type := [----------------------]; Example 5-5.
{determine pointer to parameter's location; } {addr function takes parameter as argument and returns} {address } parms[2].pd_parmptr := addr(-----------------); {determine length of parameter; sizeof function takes } {parameter as argument and returns number of bytes } parms[2].pd_parmlen := sizeof(-------------------); {reference parameter requiring byte address} parms[2].pd_parm_type := -----------------------------; {output parameter} parms[2].
{input parameter} parms[3].pd_io_type := [----------------------]; {describe FRAC -- input by value} {determine pointer to parameter's location; } {addr function takes parameter as argument and returns} {address } parms[4].pd_parmptr := addr(-----------------); {determine length of parameter; sizeof function takes} {parameter as argument and returns number of bytes } parms[4].pd_parmlen := sizeof(-------------------); {value parameter} parms[4].
begin QUIT(status.info); end; end; {stub procedure DECMADD} {end Example 5-5} Finished DECMADD Stub Putting all these pieces together yields the following stub procedure declaration (see Example 5-6): Example 5-6. Finished DECMADD (NM| > CM) Stub $os 'mpe/xl'$ $subprogram$ $standard_level 'ext_modcal'$ $tables off$ $code_offsets off$ $xref off$ $type_coercion 'representation'$ PROGRAM Xampl56(input,output); TYPE decm_number = PACKED ARRAY [1..
DIGITS FRAC) const pidt_known = pidt_load = pidt_plabel = INTEGER INTEGER 0; 1; 2; system_sl logon_pub_sl logon_group_sl pub_sl group_sl = = = = = 0; 1; 2; 3; 4; {not callable from split stack} {callable in split-stack mode} {callable in no-copy-mode} parm_type_value = 0; parm_type_word_ref = 1; parm_type_byte_ref = 2; {value parameter } {word address is required} {byte address is required} Example 5-6.
p_proc_id : bit16_a1 ); pidt_load : ( p_lib : bit8_a1; p_proc_name : cm_proc_name ); pidt_plabel : ( p_plabel : bit16_a1); end; 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; 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} Example 5-6.
proc parms method nparms funclen funcptr status cond_code : : : : : : : : scm_procedure; scm_parm_desc_array; integer; {split-stack callable?} integer; {# of parameters} integer; integer; xlstatus; ccode_type; loc_digits loc_frac : shortint; : shortint; begin { Initialize local variables } loc_digits := DIGITS; loc_frac := FRAC; { Initialize Switch variables } proc.p_proc_id_type := pidt_load; {find procedure by name} proc.p_lib := pub_sl; {look in PUB SL (LIB=P)} proc.
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].
Example 5-6. Finished DECMADD (NM| > CM) Stub, Continued {RESULT -- output by reference} parms[2].pd_parmptr := addr(RESULT); parms[2].pd_parmlen := sizeof(RESULT); parms[2].pd_parm_type := parm_type_byte_ref; parms[2].pd_io_type := [output_parm]; {DIGITS -- input by value} parms[3].pd_parmptr := addr(loc_digits); parms[3].pd_parmlen := sizeof(DIGITS); parms[3].pd_parm_type := parm_type_value; parms[3].pd_io_type := [input_parm]; {FRAC -- input by value} parms[4].pd_parmptr := addr(loc_frac); parms[4].