The Native Mode SPL Compiler for MPE/iX

Programmer's Guide

This guide is for programmers who are using the SPLash! Compiler to migrate SPL code to the MPE/iX platform or who want to continue writing code in SPL and have Native Mode performance.

This document assumes a firm foundation in SPL syntax and methodology. Much of the information in this document stresses the differences between SPLash! and SPL, so you may want to prepare for your compilation project by studying your SPL documentation in addition to this manual. Reference documents for SPL are listed in the section called "Other Sources of Information" in the first chapter of this manual.

Copyright c 1995-2003 Allegro Consultants, Inc.

ALLEGRO CONSULTANTS, INC. 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. Allegro Consultants, Inc. 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.

HP-UX, MPE V, MPE XL, and MPE/iX are trademarks of Hewlett- Packard Company.

UNIX is a trademark of AT&T Bell Laboratories.

Allegro Consultants, Inc. 1072 De Anza Blvd., Suite B101 San Jose, CA 95129-3532 USA (408) 252-2330 voice (408) 252-2334 fax support@allegrosupport.com www.allegrosupport.com



Table of Contents

(top) (index)

1   Introduction


The SPLash! Native Mode Compiler is a compiler for SPL (Systems Programming Language), Hewlett-Packard's powerful block-structured programming language. SPL was originally developed to run under the MPE V operating system and to take advantage of the hardware features of the original family of HP3000 computers. With the advent of Hewlett-Packard Precision Architecture and a new generation of HP3000s, SPLash! offers the features of the original SPL language and the opportunity to take advantage of the full native mode capabilities of the new machines.

SPLash! is a powerful tool for migrating existing SPL applications to Hewllett-Packard's Precision Architecture (HPPA). With SPLash!, there is no need to recode your programs using a different language, nor do you need to maintain original and translated versions of your object code. SPLash! gives you access to native mode performance on HP Precision Architecture machines.

SPLash! was designed for maximum compatibility with its MPE V counterpart. Since the original SPL language was highly dependent on the hardware environment of the MPE V-based HP3000, SPLash! emulates the addressing scheme of these older machines. All constructs supported by SPL are supported by SPLash!, including most ASSEMBLEs, all stack references (such as TOS and stack decrements), and all other statements. The features that SPLash! does not support generally depend on the old 16-bit architecture or other hardware features that do not exist in HP Precision Architecture. Throughout the manual, these differences are discussed as they arise.

Using SPLash!

Program development with SPLash! involves the usual cycles of editing, compiling, linking, and testing. There are two approaches to choose from in compiling your programs. One approach is based on UDCs that are provided with the product. The second approach is to use command files in the same manner that you would use for any HP compiler product. These approaches are discussed next.

Using SPLash! UDCs

Two UDC files are provided with the SPLash! compiler. The default UDCs are geared towards program development on the Spectrum, while the alternate UDCs (contained in SPLASHV.PUB.SPLASH ) function like the SPL UDCs (SPL, SPLPREP). The installation job builds the necessary account structure and initializes the default UDC file, SPLASHU.PUB.SPLASH .

When compiling with the default UDCs, SPLash! uses two groups for storage of intermediate code. These groups are ASM and O. The ASM group contains the direct output of SPLash!, the assembly language. The O group is used by the assembler. This is where the assembled output is stored. The files that are stored in the O group are native mode object files, (filecode NMOBJ). These files can be linked together with the LINKEDIT program to produce native mode programs, native mode executable libraries, or native mode relocatable libraries.

Using Command Files

If you want to use command files for SPLash! development, you can choose any one of the four command files provided for that purpose. These command files are modeled after the command file format that the HP compilers use. The command files are listed next.

Compilation Command Files

Regardless of the approach you take, it is recommended that you review at a minimum the chapters Before you start , Compiling with SPLash! , and Beyond SPL .

In most cases, very few changes are required to successfully compile your original SPL source with SPLash!. If you do need to implement source code changes, you have several resources to work with. First, SPLash! CONTROL options are provided that ease migration analysis and testing of SPL code. Second, a cross-reference utility program, XREF, is provided to help with the analysis of your SPL code. Third, several SPLash! debug macros are provided for use with the HP debugger (see Appendix E). Appendix A discusses native mode and privileged mode Assemble instructions. And finally, Appendix B covers intrinsic differences between MPE V and MPE/iX.

(top) (index)

About This Manual

This document introduces SPLash! and provides a detailed reference for programmers. Whether you are migrating existing SPL applications to HP Precision Architecture machines or whether you are taking advantage of SPLash!'s powerful language features to develop new programs, use this document along with Hewlett-Packard's SPL documentation to obtain the information you need to successfully implement your design.

The information in this document is organized into eight chapters and several appendices. Depending on your technical background and on your purpose for using SPLash!, you may want to concentrate on certain sections and skip others.

Chapter 1, Introduction, describes SPLash! at a high level. It also lists relevant Hewlett Packard publications that you may want to review as companions to this document.

Chapter 2, Installation, discusses the account structure and step by step instructions on how to install your SPLash! software.

Chapter 3, Before you start, highlights important differences between the MPE V and MPE/iX operating systems and identifies conceptual differences between the original SPL and SPLash!.

Chapter 4, Compiling with SPLash!, provides detailed information on the compilation process.

Chapter 5, Parameters, Procedures & Conventions, introduces SPLash! procedure and parameter calling mechanisms and other conventions. In addition, it lists important SPLash! register conventions that you may need to know to successfully debug your code.

Chapter 6, Beyond SPL, describes the options and features that extend SPLash! beyond the capabilities of the original SPL language.

Chapter 7, Using XREF, provides an introduction to this useful cross-reference tool for SPL programs, including a several examples to get you started.

Chapter 8, Migration Issues, provides information to help you successfully migrate an existing SPL application to your HP Precision Architecture machine using SPLash!. Porting to HP-UX is also covered in this chapter. Differences in data types, data formats, and intrinsics are also explained.

Chapter 9, Run Time Error Recovery, describes the methods supported by SPLash! for this purpose.

Appendix A, Assemble Instructions, discusses how Assemble instructions can affect your migration when language features are not supported in SPLash!.

Appendix B, Intrinsic Changes lists the intrinsics that are not supported under MPE/iX.

Appendix C, Messages , lists General Messages, Warning Messages, Error Messages and Internal Error Messages.

Appendix D, SPLash! Debugger, introduces the internal SPLash! Debugger

Appendix E, SPLash! & Debug/iX Macros, provides support for the material on Debugging with a discussion on the SPLash! Debug macros, highlighting important points as required. Included also is an introduction to Debug/iX.

Appendix F, Sample Code, provides sample programs to illustrate techniques for migrating with SPLash! and creating new applications using SPLash! extensions.

Appendix G, Technical Background, discusses the basic structure in the new architecture and the differences between MPE V and MPE/iX.

(top) (index)

Other Sources of Information

This document is intended to supplement, not replace, Hewlett-Packard's SPL documentation. For all practical purposes, it is assumed that SPLash! users have a firm foundation in SPL. The thrust of this document, then, is to educate on the differences between these two languages and to provide the knowledge necessary for migrating SPL-based code to the MPE/iX platform.

Detailed descriptions of SPL syntax and usage can be found in the following Hewlett-Packard documentation:


(top) (index)

Typeface Conventions

The following conventions are used throughout this document.


With the introduction of release 4.0 of the MPE/iX operating system, HP changed the name of the operating system from MPE XL to MPE/iX. Throughout this manual, we have tried to be consistent in our use of MPE/iX versus MPE XL. In most cases, the two words are interchangeable.

(top) (index)

2   Installation


This chapter guides you through the installation process, step by step. There are two methods for installing SPLash! so that you can choose the installation procedure that best suits your needs.

Updates can be installed over the existing SPLASH account. Or, SPLash! can be installed in a uniquely named account. The advantage of the later is that the update can be tested before being rolled into a production environment.

(top) (index)

Overwriting the SPLASH account (default)

Before updating the SPLASH account, remove any cataloged SPLASH UDCs. UDC files may be modified from update to update.

1. Logon as MANAGER.SYS

2. Mount the SPLash! update tape and place the tape drive online.

3. Restore the file SPLASH.PUB.SYS by entering the following commands:

4. Edit the passwords in line #1 for MANAGER.SYS in the file SPLASH.PUB.SYS .

5. Stream the installation job by entering the following command:

When the job for MANAGER.SYS logs off, check the $STDLIST for errors. If no errors are reported, then SPLash! is ready to use. By default, the SPLash! UDCs are only set for MGR.SPLASH, however, this is easily changed by using the SETCATALOG command.

(top) (index)

Install in Uniquely Named Account

These instructions are very similar to the above with one exception. Insert the following instruction after step 4.

4.5 After the file SPLASH.PUB.SYS is restored, use a text editor to change the line specifying the account name to the name of the account where SPLash! will be installed. Initially, this looks like the following:

For example, if you want to install SPLash! in the account named SPLTEST, you would change the setvar line to the following:

Only valid MPE account names can be used.

Note —The installation job will automatically edit the UDC and command files so that they can be used from the account that you specify.

(top) (index)

3   Before you start


When SPLash! was designed, one of the primary objectives was to achieve maximum compatibility with the MPE V based HP3000 environment. Almost all hardware dependent features were implemented, including:

As good as SPLash! is at maintaining the MPE V-based HP3000 environment, some facets of the traditional HP3000 architecture were not implemented because they were too specific, required too much overhead at run time, depended upon a property which is non-existent or meaningless in Hewlett-Packard Precision Architecture, or were obsolete. SPLash! will flag these few constructs, should they exist in your code, and outline ways in which you might change your code in order for it to compile and execute in native mode.

An example of how SPLash! flags these constructs is shown below. A line from an SPL program is shown, along with the error message that would be generated by SPLash!.

In this case, the ABSOLUTE construct, which is used to reference bank 0 of memory on an MPE V-based HP3000, is flagged as being privileged. The discussion on flagged instructions that follows describes the use of the ABSOLUTE function and why it is not recommended for use in SPLash!

Note —Almost all of the features not implemented by SPLash! are instructions accessed by the ASSEMBLE statement. These features are enumerated in the discussions that follow. Furthermore, the constructs presented in these discussions are probably the least commonly used constructs in the SPL language.

(top) (index)

The Role of Privileged Mode in SPL Environments

Over the years, much SPL code has been written to run in privileged mode (PM). The rational for this was to eliminate the normal checks of HP3000 microcode or the MPE operating system, opening up the opportunity for data to be read or modified anywhere in the system. The dangers of using PM were, in these cases, outweighed by the ability to programmatically determine information about the runtime environment. Given the constraints of the environment, such information was simply not available through standard MPE interfaces. Introducing PM code solved the information gap problem.

PM operations in the SPL environment are extremely difficult, if not impossible, for SPLash! to support. Fortunately, the paucity of PM support SPLash! isn't a problem in most cases. Standard intrinsics, as well as AIF intrinsics, offer standard, replacement solutions to outdated PM code. The primary focus of this chapter, then, is pointed towards those rare occurrences where adequate solutions are either tricky to implement or simply not available. Background information is provided, however, that may assist you in developing an optimal solution.

Compatibility Mode & Privileged Mode

Many of the HP3000 PM operations are supported by the compatibility mode (CM) emulator on MPE/iX, and are therefore supported by SPLash!. However, a general problem with PM has always been determining the function and format of the system data structures being accessed.

For a long time, information on where system data resided, how it was structured, and exactly what it was used for was unavailable until HP published the Systems Tables Manual , the MPE System Tables Diagram and other documentation. Even with these resources available, HP reserved (and still reserves) the right to change these data structures when it deems necessary.

Because of these changes to the operating system, simply updating to a new version of MPE could cause a PM program to run incorrectly or, at best, give erroneous results. It could also cause system failures and/or data corruption. This constant necessity to validate the functions of PM code is one of the prices that is paid for the added functionality and performance possible by using these programming techniques. Often, new versions of the operating system contain new functionality which negates the need for the PM code. For example, many routines have been written which programmatically determine the job/session number of the calling program. The necessity to code this function via PM was removed when the JOBINFO intrinsic was introduced a few years ago. More recently, the advent of the AIF intrinsics eliminated similar needs. Both JOBINFO and the AIF intrinsics are fully supported in SPLash!.

Philosophically, PM operations in SPL are very different from other types of statements because their semantics are totally dependent upon the surrounding environment, the data being passed to them, and the MPE system tables and other objects being accessed. For example, a standard SPL MOVE statement is very easy to understand. The concept of moving strings of data from one area of memory to another is common to all computer systems, and can be generated on the Series 900 very easily. However, the machine instruction MFDS (Move From Data Segment) relies upon the existence of data segments, a concept very specific to the HP3000 hardware architecture. Additionally, it is impossible to determine from the source code exactly what is the intended purpose of the MFDS instruction without also examining elements external to the SPL language itself, such as what system table is being used and what data within the table is being read. A MOVE statement, on the other hand, is totally self-contained and easy to understand both by humans and by the compiler.

In migrating SPL code to the Series 900 machines running under MPE/iX, it must be realized that this code is being moved to an environment totally different from that of the traditional stack-based HP3000. Not only is the hardware environment dissimilar, but the operating system (MPE/iX) has been heavily rewritten to run on this new hardware architecture.

Although the functionality of most of the MPE V tables has been duplicated in the MPE/iX tables, it cannot be assumed that these two sets of tables have the same format. Until Hewlett-Packard publishes an MPE/iX tables manual or its equivalent, these tables will remain inaccessible. A larger issue also exists: as of this writing it is uncertain how MPE/iX will map the HP3000 two-level PM scheme (user or privileged) into the four-layer ring security structure of Hewlett-Packard Precision Architecture. Until these issues are resolved, a straight migration of some SPL code running in privileged mode is impossible.

The compatibility mode emulator running under MPE/iX does simulate most privileged operations. Every attempt has been made to allow SPLash! to support those privileged operations that are present in the emulator. However, most are flagged as errors to point out the use of privileged mode in your code.

Note that although the operations included in the discussions below (unless otherwise noted) are not supported in the full release version of SPLash!, all other operations are supported. Any privileged operations not explicitly discussed in this documentation are supported by SPLash!.

In summary, migrating privileged SPL code to the Series 900 will generally require a close examination of the specific functionality desired by the code. With this understanding, the following questions should be asked:

If the answer to question 2 is yes, then those small portions of SPL code which employ PM coding techniques should be rewritten to take advantage of the new MPE/iX functionality. If the answer is no, then you may have to work with a migration specialist (perhaps from Allegro or Hewlett-Packard), to resolve the specific issues encountered in your code migration.

(top) (index)

Unsupported CM Instructions

This section documents those CM Instructions that SPLash! does not support.

Read Switch Register (RSW) Instruction

The Read Switch Register instruction was implemented originally for the Series II and III HP3000 models. The front panel on these models contained displays for two registers: the Current Instruction Register and the Switch Register. For each bit in the switch register there was a rocker switch, which allowed the operator to toggle specific bits on and off at will. When the RSW instruction was executed, it read which switches had been set on, and pushed this as a 16-bit data word to top of stack. The most common use of this instruction was by INITIAL, the system startup program. The operator would toggle in different combinations of bits, which varied with the startup method (tape or disc).

In a very few, highly specific cases, the switch register was used as a signal to applications.

On HP-IB systems, the RSW changed slightly and was used to read the channel and device word from the thumbwheel switch that corresponded to the button used for system startup. The RSW instruction was of much less use at this time.

For the 900 Series, no such toggled register exists. Applications which use this instruction as a signal must be re-coded to provide this functionality another way. Using message files and soft interrupts (which did not exist when the Series II/III were originally created) can provide this signaling capability. A description of using message files is documented in the File System Reference Manual , HP Part Number 30000-90236.

Memory Instructions


These instructions all depend upon the fact that the HP3000's memory was partitioned into banks of 64K words each in an attempt to overcome the 16-bit address limitation. All are privileged, and most are typically used only by low level system code.

Code employing any of these instructions will have to be re-examined and may need re-coding per the recommendations in the previous discussion titled "The Role of Privileged Mode in SPL Environments". SPLash! supports LDEA, LSEA, SDEA, and SSEA. The file MDS.INC.SPLASH contains details on these instructions.

Hardware Dependent Instructions

   DISP     IXIT     LOCK     PAUS     PCN      PSDB     PSEB
   RCLK     RMSK     SCLK     SED      SMSK     UNLK

These instructions are also highly privileged. These however, depend upon architectural features of the MPE V-based HP3000's rather than the memory structure. Some, such as UNLK and LOCK, were implemented to support multiple CPU's. Others, such as PSDB, PSEB, DISP, and IXIT interact with the dispatcher and ICS in a way that is highly specific to the MPE V-based HP3000's. The dispatcher under MPE/iX is not launched by microcode (there is none), and therefore these instructions have no meaning. The others are typically used by low level code in the operating system kernel. These particular opcodes are not even simulated by the compatibility mode emulator in MPE/iX.

Code employing any of these instructions will have to re-examined and re-coded per the recommendations in the discussion (above) titled "The Role of Privileged Mode in SPL Environments".

Obsolete Instructions

   CIO      CMD      HALT     RIO      SIN      TIO      WIO

Be sure to read the discussion titled "The Role of Privileged Mode in SPL Environments" in this document if you have any of the instructions listed above in your code. These instructions are all privileged and fall into the category of instructions that were implemented for specific HP3000 models. For example, the WIO, RIO, CIO and TIO instructions only existed on the HP3000 Series II/III.

If code employs these instructions, it is highly specific to a particular HP3000 series and is not transferable to a newer machine, much less to an HPPA based Series 900. It is suggested that migration assistance be employed with this type of code.

Limited Support for XEQ Instruction

The XEQ instruction allows a 16-bit word of data to be loaded on the stack, then executed by the microcode as a 16-bit HP3000 machine instruction word. This is useful for a variety of tasks.

However, fully implementing this instruction would require that SPLash! generate a run-time HP3000 machine code interpreter. On MPE V-based HP3000's, this interpreter is contained within the system microcode. No such interpreter exists in HPPA, and it was felt that the overhead was not a cost effective use of machine resources, given the number of times this instruction is used.

There exists one fairly common use of XEQ which is to build an EXIT instruction in a Control-Y handler. On stack-based HP3000's, the operating system deposits a number of words to delete from the stack when calling a Control-Y handler. The opcodes corresponding to the EXIT instruction is placed on TOS, the number of words to decrement is added to it, and XEQ 0 is executed. For this commonly encountered case, SPLash! will assume that the procedure containing the XEQ 0 is a Control-Y handler, and handle the procedure accordingly. See the section on Control-Y in Chapter 8, Migration Issues , for detailed information.

The native mode (NM) Control-Y handling is much simpler to program, and is armed with the intrinsic XCONTRAP. Unlike the standard SPL Control-Y environment, the NM Control-Y handling portion of MPE/iX cleans up the stack automatically, removing the burden from the programmer. It is recommended that the Control-Y handler be rewritten to take advantage of this superior methodology, and thus remove the ASSEMBLE(XEQ 0) altogether.

Limited Support for PCAL Instruction

Another commonly used non-privileged instruction is PCAL. The PCAL instruction has three formats. The `PCAL label' format is used to perform a PCAL instruction to a specific procedure name. This format assumes the parameters for the procedure specified in PCAL label have already been loaded onto the stack. SPLash! fully supports this format.

The `PCAL n' (n > 0) format is used to call a procedure defined by an entry in the Segment Transfer Table (STT) for that segment. In this case, `n' is an index into this table. The STT is a table of 16-bit entries at the end of every code segment. It has a specific format, and different formats differentiate between internal and external procedures. This table is known to the system microcode, and is therefore tied closely to the hardware. In order for SPLash! to implement the PCAL n format, it would have to simulate the STT, a structure which does not exist under MPE/iX. Just like the XEQ 0, it was felt that the use of this format did not warrant simulating a structure so closely tied to the microcode of the MPE V-based HP3000. If this format is being used, the PCAL label format should be used instead.

A special format for PCAL, PCAL 0, is used when it is desirable to call a procedure whose identity is not known until runtime. Typically, the intrinsic LOADPROC is called to bind a procedure in an SL to the calling program. The LOADPROC intrinsic returns a procedure label (PLABEL) which is a 16-bit quantity exactly matching the format of an STT entry. Implementation of this format would combine the runtime complexities of interpreting the TOS word (like XEQ 0) and interpreting the STT format (as with PCAL n, above). PCAL 0 is not implemented by SPLash!, but the functionality of dynamic procedure loading and calling will be accommodated through a new type of procedure, OPTION DYNAMIC. Your application will need to be re-coded to use this new feature. See the file DYNAMIC.INC.SPLASH for several examples.

Loading & Branching Instructions

   BCC      BR       LDPN     LDPP
(and related instructions)

This includes the set of instructions which loads words of code onto the stack and all instructions which can do branches. The LDPP and LDPN instructions were created to allow constants to be loaded from code. This is done if a constant in a calculation is greater than 8 bits, in which case an immediate instruction could be used. Because code is not highly differentiated from data in HPPA, instructions which specifically load code literals do not exist. SPL code that uses these assemble instructions should be re-coded to employ a simple TOS := literal (or constant) statement.

The branching machine instructions absolutely depend upon the 16-bit orientation of MPE V-based HP3000 instruction words. For example, the statement BR P+20 branches from the current location to the location 20 machine instructions away. This could very well be outside of the assemble statement and in the SPL statements occurring after the assemble. There is no problem with the p-relative branch since in standard SPL, those subsequent statements are translated into 16-bit machine instructions.

The translation of this 16-bit machine instruction word format is very difficult in HPPA. For this reason, SPLash! does not attempt to interpret what would have been generated on a stack-based HP3000. SPL code that employs p-relative addressing must be changed to use a branch to a label. For example:

    ASSEMBLE (BR P+20); . . . I := 4 + J; << P + 20 >>

must be changed to:

    ASSEMBLE (BR LAB1); . . . LAB1: I := 4 + J;

This code is easily handled by SPLash!, in addition to being far more readable and maintainable.

Pushing & Setting Registers

   PUSH and SET    Statements
   PSHR and SETR   Machine Instructions

These statements are used to manipulate the registers resident on the HP3000 processor boards. As with any architecture, the use and philosophy of the registers describes to a large extent the machine architecture itself. Since HP Precision Architecture is quite different than the traditional HP3000 architecture, some of the registers do not translate well to the new architecture.

In order to simulate the SPL environment, SPLash! maintains simulated copies of most of the HP3000 registers. Thus, Q, S, Z, and the DL registers are all available for use by the SPLash! programmer. In standard SPL, pushing the DB register is a privileged operation. In addition, it pushes the bank number and absolute offset in the bank onto the stack. As presented in Discussion 1, these concepts have no meaning on the 32-bit HP Precision Architecture. Pushing of the DB register now causes SPLash! to push the 32-bit HPPA register pointing to the simulated DB area in the SPLash! program's native mode (NM) stack.

Pushing and setting of the Status register is partially supported. Some of the fields within the status register, such as the "right bit" (which stackop is being executed) are meaningless in HPPA. The same is true of the code segment number. The following shows the status register format on MPE V-based HP3000's with the fields that are supported under SPLash! when executing the PUSH statement or PSHR instruction:

M  |  I  |  T  |  R  |  O  |  C  |  CC   |      CST #

M Set to 0 if NM exec level = 3 Set to 1 if NM exec level < 3

I Always set to 1

T Always set to 0

R Always set to 0

O Set as it would be on an MPE V-based HP3000

C Set as it would be on an MPE V-based HP3000

CC Set as it would be on an MPE V-based HP3000

CST # Always set to 0

Setting of the status register is commonly used for disabling/enabling arithmetic traps. This functionality is provided by an intrinsic under MPE/iX, and code which sets the T bit to turn off traps should be modified to use this method. Overflow, Carry, and Condition Code can be modified by the programmer and then set. All other fields are unaffected by the SET or SETR operations.

The CON Construct

   CON      EDIT     TR       ENDP     PARC     XBR

The CON construct is partially supported by SPLash!. Using CON in standard SPL, it is possible to drop any sort of data into the code stream which is subsequently interpreted by the microcode. The most common uses for CON are to build PB arrays and to form machine instructions whose assemble mnemonics are not recognized by SPL.

In the case of using CON to assemble PB arrays, the large code addressing space of the /iX overcomes some of the shortcomings of PB arrays in standard SPL. For this reason, any uses of CON for PB arrays should be removed and the array be re-coded to a standard PB array declaration.

In the case of CON being used to implement other machine instructions, this need has been removed by the fact that SPLash! will now implement the commonly used COBOLII instructions as assembly opcodes. The opcodes that will be supported by SPLash! are TR (via two new opcodes: TRDB and TRPB), ENDP, PARC, XBR (but not EDIT). See the example file PARC.INC.SPLASH for more information.

LLBL Instruction

Like the PCAL 0 instruction, this instruction relies upon the hardware dependent Segment Transfer Table (STT), and is not supported by SPLash!. If it is being used, the code should be rewritten to use the SPLash! Dynamic procedure facility.

Flagged Instructions

   MTDS     PLDA     PSTA     SST

Most of these privileged instructions are supported by SPLash! to the same extent that they are supported by the compatibility mode emulator on MPE/iX. They are flagged here as warnings that the semantics of their operation may change under MPE/iX. Please refer to the discussion titled "The Role of Privileged Mode in SPL Environments". See also the file called MDS.INC.SPLASH .

(top) (index)

4   Compiling with SPLash!


SPLash! can be used to compile standalone programs or individual modules. The output of a standalone program compilation is a native mode program file (NMPRG). While the output of an individual module compilation is a native mode object file (NMOBJ). SPLash! NMOBJs can call or be called from any other native mode language (except for procedures that are compiled with the $SPLASH compiler option). The sections that follow review the various SPLash! UDCs and command files. Several sample compilations using SPLash! are also offered.

SPLash! User Defined Commands (UDCs)

SPLash! is delivered with two different UDC files which are located in the SPLASH account: SPLASHU (default) and SPLASHV. Each UDC file contains several UDCs that can be used to compile, assemble, or link your SPLash! programs. The default UDCs are oriented towards program development on the /iX, while SPLASHV UDCs are similar in function to the SPL UDCS.

By default, the SPLASHU UDCs are cataloged when SPLash! is installed. Please refer to the HP MPE Command Reference manual for details on the SETCATALOG command if you wish to modify the SPLash! UDCs.


The UDCs in SPLASHU allow SPLash! programs to be compiled, assembled, and linked as easily as —

Or, These UDCs make four assumptions that you must follow:

The "lk" suffix for the names of the two UDCs which link programs follows the examples of the other native mode compilers in MPE/iX. The ".O" suffix for the assembler output was inspired by the C language.

The UDCs in SPLASHU.PUB.SPLASH provide quick access to the SPLash! compiler, but they require that you first define the specific group structure outlined above and then follow the conventions for maintaining your source and output files.

If you installed the software using the steps outlined in the Installation chapter, these groups will have been created for you.

Each of the UDCs are described next.

SPLASHU UDC Descriptions

SPLASHU.PUB.SPLASH contains five UDCs for compiling, assembling, and linking SPLash! programs, as described later in the chapter.

SPLLK Compiles from <source>.<logon> to <source>.ASM and then links to <source>.PUB.

SPLASH Compiles from <source>.<logon> to <source>.ASM.

ASMLK Assembles <source>.ASM to <source>.O, then links to <source>. PUB.

ASMOBJ Assembles <source>.ASM to <source>.O.

SPLOBJ Compiles and Assembles from <source>.<logon> to <source>.O.


The UDCs in SPLASHV closely parallel the MPE commands: SPL, SPLPREP, and PREP. They make no assumptions about naming conventions.

SPLASHV UDC Descriptions

SPLLK Compiles from <source>, assembles, links; the result is in $OLDPASS.

SPLASH Compiles from <source>, resulting in SPLASSM.

ASMLK Assembles <source> to $NEWPASS, then links $OLDPASS to $NEWPASS.

ASMOBJ Assembles <source> to $NEWPASS, for deferred linking.

UDC Parameters

This section discusses UDC parameters for all of the SPLash! UDCs.

    Parameter   Default   Description

   source      The name of the file to be compiled or assembled. You must specify this parameter; there is no default value.

   parm   0   This parameter is reserved for use by SPLash! developers. Do not specify a value other than the default. Note that this parameter is different from SPL's parameter of the same name. Unlike SPL, the SPLash! compiler automatically opens the formal files SPLTEXT, SPLLIST, and SPLASSM; you need not specify a compilation parameter to accomplish this.

   priv   3   Specifies the privilege level to be assigned to your program's outer block. When your program runs, it will automatically execute at this privilege level. Two values are allowed:

   3 = User Mode    2 = Privileged Mode

   Values 1 and 0, which represent more powerful privileged modes, are not allowed by Hewlett-Packard. The MPE/iX loader will not load a file linked with privilege level 1 or 0.

   cap   "ia,ba"   Specifies the capabilities to be assigned to your program when it executes. When coding this parameter, you must specify one or more of the following capabilities, separated by commas and enclosed in quotes.

ia Process can run interactively.

ba Process can run in batch.

mr Process can access multiple system resources concurrently.

ds Process can create and use data segments.

ph Process has the ability to perform process handling. It can control or create other processes and can obtain information about executing processes.

pm Process can run in privileged mode (that is, at ring level 2) or can call procedures that run in privileged mode. Note that this is different from the priv parameter, described above, which specifies the default execution mode for a program's outer block. You can specify pm for modules as well as programs; they will not begin executing in privileged mode but will be able to switch to privileged mode execution or to call privileged procedures.

   arecs   40000   Specifies the maximum size, in records, for the intermediate assembler file generated by the SPLash! compiler. If this file is not big enough, the compiler will complete its processing and then issue a message indicating how big the file should be.

   orecs   2000   Specifies the maximum size, in records, for the native mode object (NMOBJ) file that the assembler produces after processing the SPLash! compiler output. In MPE/iX, the NMOBJ file is equivalent to SPL's USL file.

   opt   " "   Specifies optional text that you wish to pass to the assembler.

   info   " "   Specifies an optional text string that contains compiler directives. Code one or more compiler control options separated by commas; enclose the list in quotes. (See Chapter 6, Beyond SPL for a list of compiler control options.) Do not include a $ before the first option; the SPLash! compiler will automatically insert this symbol. The compiler will interpret this string as the first line of compiler input.

   list   $STDLIST   The default for the SPLASH UDCs in both SPLASHU and SPLASHV is $STDLIST, for the other UDCs (e.g. ASMLK, ASMOBJ, etc.) the default is $NULL.

Compiling Standalone SPLash! Programs

This section shows, through examples, how to use the SPLash! UDCs to compile, assemble, and link a standalone program. These examples use the UDCs provided in SPLASHU which are described earlier in this Chapter. It may be helpful to review that section if you haven't already done so.


Suppose you have created a SPLash! program by entering source code into a file named FOO in your logon group. To compile this program, just type:

The "splash" UDC compiles the source file and generates a file with the same name in your ASM group. This new file, FOO.ASM, contains assembly language code. The listing is routed to $STDLIST. Since no additional parameters are specified, the default values are used, as described earlier in this section. Note that, like SPL, SPLash! produces machine code even if syntax errors are found (although this means that the code generation process might fail).

If you wish to specify parameters, you can do so the same way that you would for any UDC: by coding positional values or by preceding values with parameter keywords. Note that if you use positional values, you must specify values in the proper order and separate them with commas. If you use keywords, you can specify the parameters in any order, but you must separate them with semicolons.

For example, using positional parameter values, you can compile the program FOO using a larger intermediate assembler file and send the listing to a deferred printer by typing:

Or, you can compile the program and suppress the listing, using keyword parameters, by specifying:

If you want to compile a larger assembler file (80000 records), and send the listing to a deferred line printer, you would issue the following commands:

Assembling & Linking

After successfully compiling the program FOO, you must assemble and link it before executing it. You can use the "asmlk" UDC to assemble from FOO.ASM to FOO.O, then link FOO.O to FOO.PUB, by typing:

To assemble FOO.ASM to FOO.O and then link FOO.O to FOO.PUB with privlevel 2 (privlev 2 corresponds to MPE V's PM) you would issue the following statement:

This is the privlevel needed to be able to perform "privileged" operations, like opening a file with a negative file code. Note that the MPE XL loader will refuse to load a file linked with privlev 0 or 1.

Alternatively, you can perform the same steps using the "asmobj" UDC with MPE/iX LINK command using the following statements:

When your program consistently compiles cleanly, you may want to compile, assemble, and link in a single step. To do this, use the "spllk" UDC, which is similar to the SPLPREP command. For example:

This UDC compiles FOO (in the logon group) into FOO.ASM, then assembles it to FOO.O, then links it as FOO.PUB.

(top) (index)

SPLash! Command Files

These command files are functionally similar to the compiler command files that HP provides with their compiler products. These command files are located in the PUB group. In order to use these files, you should either move them to PUB.SYS or to a group that is in the path (HPPATH) for SPLash! users.

Like HP's compiler command files, SPLash! command files do not rely on the presence of special groups nor are they limited to compiling files in the current group. There are 4 command files for the SPLash! compiler.

Compilation Command Files

Unlike the HP compiler command files, the SPLash! command files have several parameters used during the assemble stage. These parameters, along with the standard parameters, are explained next.

Command File Usage

The contents of command file are listed next.

splxl    [text][,[asm]][,[list]][,[info]]

splobjxl [text][,[obj]][,[list]][,[info]] [,[parm]][,[arecs]][,orecs]

spllkxl [text][,[prog]][,[list]][,[info]] [,[parm]][,[arecs]][,[orecs]][,[cap]][,priv]

splxlgo [text][,[list]][,[info]] [,[parm]][,[arecs]][,[orecs]][,[cap]][,priv]

Command File Parameters

The following list describes each of the parameters used in the command files.

Note —Detailed information on these parameters is explained in the section called UDC Parameter.

Subprogram Compilations Using SPLash!

You can code a SPLash! module and then call it from a SPLash! program, another native mode language program, or both. This section describes which options to specify and how to compile your module.

Examples in this section assume we have a source module called UPSHIFT.MODULE which contains the following code:

Also, we have a program called UPPER.SOURCE which is:

    begin ! upshifts INFO text and prints it

    integer info'len = q - 6; byte pointer info'text' = q - 5; intrinsic print;

    procedure upshift (text', bytes); value bytes; byte array text'; integer bytes; option external, splash;

    upshift (info'text', info'len);

    print (info'text', - info'len, 0); ! gets a warning


In compiling and assembling a module (i.e., not a standalone program), the SPLOBJ UDC is useful.

The next examples illustrate this process using the UPSHIFT module and the program UPPER.SOURCE for both the UDC and the command file approaches to compilation.

Compiling & Assembling with the SPLash! UDCs

Compiling & Assembling with the SPLash! Command Files



Mixed Language Compilations Using SPLash!

This section discusses using SPLash! to compile a module which will be used by another native mode language program.

Note —SPLash! prefers to pass its parameters on the stack via SPL, while most other native mode languages prefer to pass their parameters in a combination of registers and the stack.

Unlike other NM languages, SPLash! generates procedures with either type of parameter passing. The OPTION SPLASH and OPTION NATIVE syntax is used to state whether a particular procedure uses stack-based (splash) or register-based (Native) conventions.

The following example uses the same upshift procedure, but this time it is called from a Pascal/iX program called UPPAS.

The UPPAS Source File

The following commands prepare and run the program. Note that since we are now calling UPSHIFT from Pascal/iX, which uses the native mode conventions for calling procedures, we must identify UPSHIFT as a native mode procedure. We do this with a $CONTROL NATIVE option on the compile.

Compiling & Assembling with the SPLash! UDCs

Compiling & Assembling with the SPLash! Command Files



Calling a Module

This section discusses compiling separate modules with SPLash! and then calling them from both SPLash! programs and from other native mode language programs.

In the previous example, if the UPSHIFT routine is compiled as:

Then, it can be easily used by other native mode language programs as shown earlier. But, it can also be called by SPLash! programs if the procedure is referenced by specifying "OPTION NATIVE" in its external declaration:

(top) (index)

5   Parameters, Procedures & Conventions

Native Mode Concepts

This section discusses concepts used throughout this manual. The information in this chapter will effect how you declare variables, procedures, and intrinsics. A table on SPLash! register usage is included at the end of this chapter.


The HP Precision Architecture demands that data is "aligned" to a natural boundary. This means that a 32-bit data item must start at an address which is a multiple of 32 bits (or 4 bytes), and so on for 8, 16, 32, and 64-bit data items.

If a program tries to reference data that is not properly aligned, an "alignment trap" occurs, and the program is aborted. Most intrinsics with reference parameters are written to allow un-aligned parameters. This was necessary to be able to migrate MPE V programs with data that was only 16-bit aligned to native mode. One example is the FGETINFO intrinsic. The eleventh parameter, "eof", is a double (32-bit integer) by reference. Native mode programs that call FGETINFO to determine the eof of a file need only pass an address that is 16-bit aligned.

Unfortunately, a small number of intrinsics have parameters that must be 32-bit aligned. One example is the GETHEAP intrinsic. The by-reference pointer parameter (a 32-bit address) must be 32-bit aligned.

In MPE/iX, an intrinsic is solely and specifically a procedure with a description in the SYSINTR file or the SPLINTR file. The code for intrinsics resides in NL.PUB.SYS or SL.PUB.SYS . Most, but not all, intrinsics are in the NL with uppercase names. In MPE V, the term "intrinsic" was used in a looser sense to mean any procedure that was in SL.PUB.SYS , including undocumented and uncallable procedures.

Passing Parameters
SPLash! provides two different methods for passing parameters to procedures: native-mode and splash-mode. You can choose one or the other, depending on the language used in the calling program and the procedure.

Native-Mode Procedures
A native-mode procedure expects to receive its first four parameters in registers and the remainder on the native-mode stack. This is the protocol used by the MPE/iX languages. For example, all procedures written in Pascal/iX, COBOL/iX, and FORTRAN/iX are native-mode procedures. While a native-mode procedure can be called from either a native-mode or splash-mode procedure, it can only call other native-mode procedures.

Refer to the HP manual Procedure Calling Conventions Reference Manual for a complete description of the parameter passing convention.

Splash-Mode Procedures
Splash-mode procedures expect to receive parameters via the SPLash!-supported stack. This is the convention established in SPL, and SPLash! implements this mode primarily to maintain backward compatibility with existing SPL applications. A splash-mode procedure can only be called by another splash-mode procedure. It can call either splash-mode or native-mode procedures, however.

Controlling the Mode with Compiler Options
SPLash! supports compiler control options that can be specified at compilation time to determine how the compiled program or subprogram will be called.

   $control internal=native    Indicates that all internal procedures, i.e. all procedures actually coded within the module, are native-mode procedures. (Do not confuse the concept of an internal procedure, as defined above, with SPL's "option internal;". They are not related.)

   $control external=native    Indicates that all external procedures, i.e. procedures defined with the EXTERNAL procedure option, are native-mode procedures.

   $control native    Specifies that all procedures, whether internal or external, are native-mode procedures. Specifying this option is equivalent to specifying:

    $control internal=native, external=native

   $control internal=splash    Indicates that all internal procedures splash-mode procedures.

   $control external=splash    Indicates that all external procedures are splash-mode procedures.

   $control splash    Specifies that all procedures, whether internal or external, are splash-mode procedures. Specifying this option is equivalent to specifying:

    $control internal=splash, external=splash

Controlling the Mode with Procedure Options
You can also use procedure options to identify whether a particular procedure is a native-mode or splash-mode procedure. There are two procedure options that you can use:

   OPTION NATIVE   Indicates that you are declaring a native-mode procedure.

   OPTION SPLASH   Indicates that you are declaring a splash-mode procedure.

You can use one of these procedure options for either external or internal procedures. When you specify the parameter passing protocol with a procedure option, it overrides any compiler control options that you specify at compilation time. For example, if you code a procedure with OPTION NATIVE, it will be treated as a native-mode procedure, even if you specify $CONTROL SPLASH at compilation.

(top) (index)

Default Parameter Passing
If you do not explicitly identify a procedure as native-mode or splash-mode through a procedure option, SPLash! determines that it is one or the other based on the previously specified compiler control options. The following table lists program and subprogram procedure defaults.

If a particular procedure declaration does not specify "splash" or "native", a default is chosen depending on several considerations. The following table shows the various combinations. Defaults were selected based on how separate compilations would most likely be used.

In the following table, combinations that produce the same results for a given type of compilation are grouped together:

Note 1: This is the default for programs.

Note 2: This combination is not meaningful, as native-mode procedures cannot call splash-mode procedures.

Note 3: This is the default for subprograms.

(top) (index)

SPLash! HPPA Register Usage

The MPE/iX debugger can be a valuable tool for debugging SPLash! programs. In order to use the MPE/iX debugger most effectively, it is very helpful to know how SPLash! uses the native mode registers.

If you are comparing the running of a CM SPL program versus a SPLash! program with the debugger, prep the CM SPL program with ZERODB, otherwise the un-initialized areas in the CM program's stack may contain strange, misleading values.

Specifying the $CONTROL STMT option in SPLash! is vital when using the debugger to debug a program. This option helps you reference source lines in the SPL file.

Register usage:

(top) (index)

6   Beyond SPL

Extensions to SPL

This chapter describes the ways in which SPLash! extends the basic SPL language to provide complete access to the HP3000. Topics include variable declaration, procedure options, compiler dollar options, AIF usage, and non-local jump constructs.

(top) (index)

Variable Declaration: VIRTUAL & FULLVIRTUAL

SPLash! has two additional keywords that can be used to declare variables: VIRTUAL and FULLVIRTUAL. Variables can be declared as normal, or have an optional "virtual" or "fullvirtual" preceding them.

Type OPTION NATIVE procedures implicitly change all reference parameters to type "virtual" if neither "fullvirtual" nor "virtual" is explicitly specified.

VIRTUAL ( ) and FULLVIRTUAL ( ) accept constants and expressions. Constants and expressions are evaluated and treated as 16-bit addresses to be converted into 32-bit or 64-bit addresses. If the constant or expression in the parenthesis is a non-byte expression, then SPLash! performs a word-to-byte conversion before the 16-bit to 32/64-bit conversion.

Note 1 Converting negative constants or expressions into 32-bit addresses will not be very useful unless you have set $DL to a non-zero value.

Note 2 The constant value zero (0) is treated as a special case by VIRTUAL ( ) and FULLVIRTUAL ( ). The constant zero (0) is treated as 0d by VIRTUAL ( ), and 0L0 by FULLVIRTUAL ( ). All other constants are (possibly doubled then) added to R4 to convert them into 32/64 bit addresses. The special treatment of zero (0) preserves compatibility with earlier releases of SPLash! which allowed constructs like:

An example of using FULLVIRTUAL is shown below, comparing it to a similar Pascal/iX procedure:


SPLash! accepts the dollar sign as a hex constant specifier. For example, $1234 == %(16)1234. As usual, double precision is indicated by appending a blank, and then a "d". For example, $C0000000 d .

Parameter Types

Procedures with checkable ANYVAR parameters were passed "4" as the hidden size value, regardless of the size of the actual parameter. SPLash! will now pass a size of 1 for simple byte variables/pointers, 2 for logical and integer variables/pointers, 4 for real and double variables/pointers, 8 for long variables/pointers, and 4 for all array variables.

Although the ANYVAR parameter type was provided to CALLING Pascal/iX procedures, a SPLash! procedure with body code can have ANYVAR parameters, with one limitation: the parameters cannot be directly accessed (because SPLash! cannot detect parameter type). Furthermore, an actual parameter passed to an ANYVAR parameter is always passed as a 32-bit address.

The following code fragment shows an example of using ANYVAR parameters:


    integer ktr;

    byte b;

    procedure zap (foo); anyvar foo; begin

    double addr'foo = foo, sizeof'foo = foo + 2; virtual byte pointer foo' = foo; integer bytes;

    bytes := integer (sizeof'foo);

    if bytes > 0 then begin ! erase with a ripple-move... foo' := 0; move foo' (1) := foo', (bytes - 1); end;

    end <<zap proc>>;

    ... zap (ktr); zap (b);

SPLash! also allows "option uncheckable" as a procedure option.

DB and Q Addresses

In SPL the maximum DB address directly addressable was DB+255; in SPLash! it is DB+4095. This area is referred to as the "Primary DB" area. The total amount of DB storage area available is 65535 bytes.

In SPL the maximum Q address directly addressable was Q+127; in SPLash! it is Q+4095. This area is referred to as the "Primary Q" area. Note that SPLash! does not detect overflow of Q-relative storage.

Procedure Options

The following options are all available in the "option" statement of a procedure declaration.

Allocates a 32-bit storage cell to hold a plabel. When a procedure marked "option dynamic" is called, SPLash! fetches the plabel from the storage cell and executes a dynamic procedure call on it. This is a high-level replacement for the "assemble (pcal 0)" construct.


The Dynamic option was a necessary enhancement to allow the dynamic calling of native-mode procedures, since (unlike SPL) SPLash! needs to know the exact calling sequence of a native-mode procedure to pass the parameters correctly.

The Extensible option tells SPLash! to pass a "hidden" first parameter to the (native-mode) procedure which is the parameter number (1-based) of the last valid parameter of each procedure call. For example, a call on HPFOPEN with 6 parameters would pass a hidden "6" in register 26.

As in SPL.

As in SPL.

As in SPL (inhibits exporting of procedure name).

Intrinsic is a (temporary) kludge option. An external native-mode variable procedure that is also marked as "intrinsic" will not have a parameter mask passed as a hidden first parameter. "Intrinsic", along with variable and extension provides the following combinations:

At present, omitted parameters default to 0 (with the exception of about 24 intrinsics that have non-zero default values.)

States that a procedure expects parameters to be passed in registers and the native-mode stack.

States that a procedure is not expected to return a condition code. Additionally, the state of the condition code is not defined after such a procedure is called.

We strongly suggest specifying "option nocc" on all native mode procedures that are not expected to return a condition code. In order to properly set up the condition code after calling a native-mode procedure, SPLash! must emit a call to the intrinsic CCODE, which is not a cheap intrinsic.

This option causes the procedure to be run in privileged mode, assuming that the user running the program is allowed to execute in privileged mode by the operating system.

The Quick option tells SPLash! that a splash-mode procedure does not expect to pass back to the caller anything in the status register and that the X-register should not be saved across the procedure call (thereby saving a few instructions).

Note —At present, Quick only applies to splash-mode procedures. It will later be expanded to native-mode procedures.

States that a procedure expects parameters to be passed on the SPLash! stack.

The Uncallable option is currently ignored.

Procedures marked as "option uncheckable" will not have a hidden size parameter passed into their ANYVAR parameters.

By default, procedures are imported (or exported) with lowercase names. Specifying "option uppercase" causes a procedure to be imported (or exported) in uppercase.

Note —SPLash! does not currently have an "alias" option, although is planned.

Because most of the intrinsics in NL.PUB.SYS are in uppercase, most of the procedures declared via a simple intrinsic statement (one which does not specify a user-intrinsic file) are imported in uppercase. SPLash! has an exception list (primarily IMAGE's DBxxxx intrinsics, and the V/3000 intrinsics) that are imported in lowercase. When ready, the new intrinsic mechanism will correctly handle all intrinsics in the SYSINTR.PUB.SYS file.

Intrinsics declared in user-intrinsic files are assumed to be in lowercase.

For splash-mode procedures, the Variable option behaves like SPL. For Native-mode procedures, a parameter mask is passed only if the procedure was not declared as "option intrinsic".

Note —SPLash! provides "option variable,intrinsic" to simulate the way PASCAL/iX implements intrinsics with optional parameters. When invoked, the statement "option variable,intrinsic" tells SPLash! that the callers of this procedure may omit parameters, however the "intrinsic" flag tells SPLash! that they should not pass the hidden parameter mask at Q-4.

SPLash! Compiler Dollar Options

SPLash! recognizes all of the compiler control statements of SPL as well as a number of new options.

SPLash! allows multiple dollar options on a single line. The word "CONTROL" is optional and all types of compiler options may be intermixed on a single line. For example, the following code segments are equivalent:


In a multiple-option statement, dollar signs ($) are treated like commas (,).

With the exception of quoted string parameters, options must be complete on a single line of input. Options using quoted strings (e.g., COPYRIGHT or TITLE) can be continued on subsequent lines terminating all lines but the last with an ampersand (&).

Dollar Options: INFO parameters and SPLASHG

If SPLash! is run with an INFO parameter, that text is used as the initial dollar options. Currently, SPLash! limits the INFO string to 72 bytes. If SPLash! detects more than this amount, a warning is generated. Examples of running SPLash! with an INFO parameter are:



In addition to using an INFO parameter to pass dollar options to SPLash!, dollar options may be placed in the file SPLASHG.PUB.SYS ("G" stands for Global). If SPLASHG.PUB.SYS exists, then SPLash! automatically uses its contents as input. Using SPLASHG provides a central location for placing site-wide, common directives.

If SPLASHG.PUB.SYS does not exist, no error message is given and no extra output appears on the compilation listing. However, if SPLASHG.PUB.SYS exists, then the records will be listed just as any other $INCLUDE file records would be listed (assuming $LIST is in effect). SPLASHG.PUB.SYS may be file equated to a different file.

During SPLash!'s first pass it looks at the INFO string for the option "NOSPLASHG". If the option isn't found, SPLash! opens and parses the option list in SPLASHG.PUB.SYS . Next, the INFO= string is parsed. After SPLASHG and INFO= are parsed SPLash! proceeds with processing the remaining code in the source file. Knowing the order in which SPLash! processes allows you to keep your "standard" options in SPLASHG, and then override them with INFO= when necessary.

Dollar Options: Reference Listing

This section lists each option. Descriptions, syntax, and examples are included as needed.


In showing the syntax of the options, brackets ([ ]) enclose optional parameters. Braces ({ }) enclose a list of parameters from which exactly one choice must be made. Most options may be preceded with "[NO]" at the start of the option name. For example:

In some of the options the phrase "at the end of compilation" is used. This means: "as of the time when the final END. is read.".

Comments in the form of "<<....>>" are allowed in compiler option lines. Comments of the form "!" throw away the rest of the option line.

Because SPLash! accepts multiple options on a single line, all options are listed below in a single alphabetic list, even though the SPL manual would have grouped "CONTROL" options separately from options like "IF" and "PAGE".

The ADDRARITHMETIC compile $ option is used to tell SPLash! how to interpret address arithmetic. By default, SPLash! allows all forms of address arithmetic. When you use SPLash! to migrate to native mode, using the ADDRARITHMETIC=WARN option setting can be very helpful in identifying questionable uses of address arithmetic.


    virtual integer pointer vip;

    @vip := @vip + 1; ! BAD, no warning/error

    $addrarithmetic = warn @vip := @vip + 1;


    @vip := @vip + 1;


ADR causes SPLash! to report the DB / Q / S relative address assigned to each variable as the variables are declared. ADR also displays the addresses of parameters to native mode procedures (the parameters known at the time of entry). The format for the ADR output differs from that generated in SPL. An example for ADR output is listed next.

ALIGN tells SPLash! to allocate 32-bit and 64-bit variables on 32-bit boundaries rather than on 16-bit boundaries. This applies to outer-block variables and 32 bit variables in native mode. Using this option can significantly reduce the number of instructions required to load and store 32-bit and 64-bit variables.

The following example illustrates before and after results from using the $ALIGN option.

First, run SPLash! without specifying $ALIGN. This is the same as running SPLash! with $NOALIGN. SPLash! defaults to $NOALIGN.

If ALIGNED32 is true at of the end of compilation, then SPLash! assumes that the addresses of all 32-bit variables are 32-bit aligned. Then, instead of emitting a three opcode sequence to load or store to such a variable, a single LDW or STW is emitted.

Note —In many cases, using the $ALIGN option has the same effect on code generation.

If ALIGNED32ALL is used with $ALIGN, all outer block arrays (virtual and non-virtual) and all native-procedure arrays (virtual and non-virtual) will start at those addresses with a virtual-address of a multiple of at least 4.

When selected (ALLOCQ), SPLash! will not assume that all procedure local-variables are allocated storage space in a clean manner. This means that SPLash! will emit extra instructions than would have been necessary in a cleanly coded program.

When turned off (NOALLOCQ), SPLash! will assume that all local variables have their storage space allocated by SPLash!, and not by the user. This allows a small speed gain for many procedures.

The following code will not work correctly when NOALLOCQ is used:

If ALLOWBYTES is on at end of compilation, then byte-pointer and byte array parameters are not half-word aligned when passed into procedures, as they would be on MPE V/E (or when NOALLOWBYTES is in effect).

ASMCOMMENT controls whether or not SPLash! emits comments along with the generated assembler code. If NOASMCOMMENT is in effect at the end of the program, then no comments will be generated. When comments are being generated, the summary at the end of compilation will list the number of comment lines in the assembler output (as opposed to code (optionally) plus comments).

ASMCOPYRIGHT controls whether or not SPLash! emits $COPYRIGHT and $VERSION strings into the assembler output.


$BASE = {8, 10, 16}


When selected, $BIGDIRECT tells SPLash! to allow direct arrays to be any size up to 32767 halfwords rather than the SPL limit of DB + 4095 halfwords of direct storage.

When selected, $BIGPROGRAM allows SPLash! to emit slightly longer code sequences for branches, enabling very large programs to be compiled. If SPLash! detects large IF and WHILE statements during compilation, it will suggest that you enable $BIGPROGRAM.

Note —This option is conceptually different from the $BIGCOMPILE$ control of Pascal/V, which primarily affects the compiler's ability to ACCEPT large programs.

(top) (index)

When a breakpoint is encountered, the code will be trapped by the operating system. If the specific type of breakpoint encountered is "armed" for the process (by the debugger), then the debugger is entered, otherwise execution resumes at the next instruction.

CARRY is maintained in register R9. Bit 31 is used to remember CARRY. When CARRY = IGNORE, the SPLash! compiler ignores the influence of any operation (arithmetic or other) on the setting of the carry bit, with the exception of the SCAN statement.

When CARRY = DETECT, the SPLash! compiler emits code that properly sets or clears the carry bit after arithmetic operations or type transfer functions.

Example: CARRY generation can be requested by doing the following.

    $CARRY = DETECT I := INTEGER (D); $CARRY = IGNORE <<if desired>>

Note —Unless your program really checks CARRY, choose $CARRY=IGNORE. This is the default setting. Using $CARRY=IGNORE saves several instructions for every statement that would generate a CARRY change.

If NOCC is set when a procedure declaration is recognized by SPLash!, then an implicit "option nocc" is added to the procedure's header. If CC is set (default) when a procedure declaration is seen, and if no "option nocc" is seen, then the procedure will generate code to pass back the condition code via the simulated status register. $CC and $NOCC do not affect intrinsic declarations.

This option changes the effect of $NOCC and $CC. In prior versions of SPLash!, $NOCC affected both procedures and intrinsics. Now, $NOCC and $CC affect only those procedures declared with the keyword "procedure". CCINTRINS affects only those intrinsics declared via the "intrinsic" keyword. By default, almost all of the intrinsics will have the CC flag enabled.

The following example shows the effects of these options. Implied in this example is that each procedure declaration is followed by a "body" or by an "option external".

Procedure Return Status Example

This option adds checking code to the runtime stack which calls the QUIT intrinsic if an overflow or underflow condition is detected. To operate correctly, CHECKSTACK must be linked with CHECKSP.O.

CLEANFOR tells SPLash! that all FOR loops are "clean". A clean FOR loop is one that does not index into the stack. Likewise, it does not change the FOR loop limit value, increment value, or counter address.

CLEANFOR results in significant speedups for FOR loops and is the default value used by SPLash!. If a program is compiled that contains a FOR loop which alters the FOR loop control values, then NOCLEANFOR should be used. In this case, SPLash! will emit extra code. The FOR loop will execute properly, but slower than it would otherwise.

FOR loops whose counter variables are of type logical or double (two SPLash! extensions) are always considered to be clean for loops.

Accepted, has no affect in SPLash!

When $COERCE is selected, untyped constant numbers (e.g., 2, -2) used in dyadic expressions with a variable (e.g., FOO + -2) are automatically coerced to the same type as the variable. This is correct in most cases, but because SPLash! emits code to evaluate 16-bit expressions using 32-bit registers, a problem arises when emitting code for expressions where constants with a "-" are used. The following example, which works in SPL ONLY because the logical add operator (LADD) never causes an overflow, will not work correctly in SPLash! when COERCE is on:

The desired result is to pick up one byte from ba (4). Instead, SPLash! picks up one byte from ba (65540). This happens because we coerced the "-2" into 65534, or $fffe.

A simple patch to the SPLash! compiler to drop the coercion would have created a bug in the code emitted for: double (six + -2) and would have resulted in a very large negative number.

When $COERCE is selected (default), and SPLash! sees an apparently negative constant which is being coerced to a logical, warning #68 will be emitted:

Note that this message might appear twice due to a quirk of SPLash!'s parsing. However, code will be emitted as before.

When $NOCOERCE is in effect, and SPLash! sees an constant (signed or unsigned) used in a dyadic expression with a logical variable, it will leave it classed as an integer.

$COPYRIGHT "text"  
Use of the copyright command will cause "text" to be inserted into the NMOBJ and NMPRG files. COPYRIGHT emits a ".COPYRIGHT" assembler directive for the first line of text (the assembler limits us to emitting only one line of copyright text of about 60 characters, the rest of the copyright text is emitted with assembler ".VERSION" directives). This command must precede the outer block BEGIN statement.

For example:

In a future release, this option will allow C style strings.

$DEBUG [debugger command]  
If any text follows the "$DEBUG", it is passed to the SPLash! debugger, executed, and compilation continues. If no text is present, the debugger is entered and will prompt for input. In the latter case, the debugger can be exited by typing "/" or "Exit". Other SPLash! compiler options should not be on the same line as the $debug option.

For information about the debugger, run SPLash! interactively and ask for debugger help as follows:

If DEBUGATEND is true at the end of compilation, it invokes the SPLash! debugger after generating code.

Accepted, has no affect in SPLash!. In SPL, the DEFINE option told the compiler to store the text of "defines" in a file, not in the stack. This option was used to compile very large SPL programs. SPLash! always stores the text of defines outside of its stack.

DIRECT tells SPLash! to allocate arrays as direct arrays, even if the "=DB" or "=Q" option was not specified. NODIRECT (the default) causes SPLash! to obey the normal rules for making arrays direct or indirect. DIRECT/NODIRECT may be intermixed at will. Whenever an array declaration is compiled, the last seen DIRECT/NODIRECT will be used.

$DL = #  
Controls the initial (and maximum) size of the DL area for SPLash! SPLash! will use the largest value seen during a compilation. The # is the number of half-words (16-bit words) that should be allocated below DB for DL-DB addressing. The maximum value is 32767.

Note that SPLash! emits much faster code when no DL-DB area is being used.

$ECHO "text"  
The text string will be echoed to $STDLIST via the PRINT intrinsic.

The $EDIT commands of SPL have not been implemented. No other compiler options may follow EDIT.

$ERRORS = #  
Sets the maximum number of errors allowed during compilation to #. If # is exceeded, then the compilation terminates. The default is 100.

EXTERNAL specifies the default mode of external procedures. If a procedure is declared as "option external" with neither SPLASH nor NATIVE being specified, then its mode is derived from the EXTERNAL= option. This is covered more fully in the chapter on separate compilation.

Used with $MILLIMOVE to tell SPLash! that MOVE instructions that follow will not have overlapping source and target addresses. See $MILLIMOVE for an example.

Broken into separate dollar options. (See ALLOCQ, CLEANFOR, OPTMOVE, and NEWDLDB.)


If GENCODE is not selected at the end of compilation, then machine code will not be emitted.

If GENSTAT is selected when the "end." statement is detected, then SPLash! will report its progress in generating code. If NOGENSTAT is in effect, then the progress reports will be suppressed.

If HARDWARN is selected, then all non-suppressed warnings are treated as errors.

$IF X# = {ON, OFF} THEN  

IMPORTDB is used to tell SPLash! that a native-mode procedure within a subprogram compilation will be called (directly or indirectly) from a SPLash! program. IMPORTDB causes such calls to "import" the SPLash! DB register, which allows these procedures to access the global variables of the SPLash! program. NOIMPORTDB tells SPLash! to simply "build" a new DB register at procedure entry time.

$INCLUDE filename  
INCLUDEs may be nested up to 127 deep. QEDIT files are acceptable, as well as "flat" files, KSAM files, and HFS filenames. No further compiler options may follow the include filename on the same line.

INFO causes the compiler to emit code that grabs the INFO string and PARM value via the GETINFO intrinsic and put the data on the SPLash! emulated stack, just as in MPE V. NOINFO suppresses this code. When NOINFO is in effect, outer block variables equated to Q-4, Q-5, and Q-6 are not very useful.

If INNERLIST is true at the end of compilation, then the assembly code generated will be sent to SPLLIST (list file) as well as to the SPLASSM (Assembler file) file.

INTERNAL specifies the default mode of non-external procedures. If an "internal" procedure is declared with neither SPLASH nor NATIVE being specified, then its mode is derived from the INTERNAL= option. This is covered more fully in the chapter on separate compilation.

Note —"internal" is quoted to differentiate it from the "option internal" concept.

$LINES = #

As in SPL, except it can be overridden by NEVERLIST.

Controls the case of the external names of any intrinsics declared after this option is detected. If LOWERCASEINTRINS is selected, then the intrinsics are assumed to have lowercase external names.

This option is generally used only with SPLINTR- format files.

Tells SPLash! that intrinsic file procedure names in the SYSINTR- format should be downshifted to lowercase.

$MAIN = "program name"  
MAIN is used to define a program name that will be printed at the top of every page of compiler listing.

If MAP is true at the end of compilation, a sorted symbol table will be produced. The compiler option BASE can be used to change the RADIX of offsets generated by MAP.

MAPBYTE causes $ADR and $MAP to report BYTE offsets from DB and Q (instead of half-word offsets like SPL).

$MPE "text"  
The MPE command executes the specified text as an MPE command, by passing it to the COMMAND intrinsic. If an error occurs, it will be reported to $STDLIST. This command is useful at the end of a compilation: $mpe "TELL MGR.SPLASH; Hit the end of the source file"

NOMILLIMOVE causes MOVE statements and expressions to compile into inline code. If MILLIMOVE is true, then MOVE statements and expressions will compile into calls to the SPLash! "move" millicode. The object file containing the "move" millicode is MOVEO.MILLI and must be linked into the final program file.

The following example illustrates compiling and linking with $MILLIMOVE, $MILLISCAN, or $FASTMOVE. Note that $FASTMOVE can only be used for non-overlapping moves.

NOMILLISCAN causes SCAN statements and expressions to compile into inline code. If MILLISCAN is true, then SCAN statements and expressions will compile into calls to the SPLash! "scan" millicode. The object file containing the "scan" millicode is MOVEO.MILLI and must be linked into the final program file. See $MILLIMOVE for an example.

If NATIVE is true, then this is equivalent to:

Otherwise, it is equivalent to:

This option must occur before the first BEGIN.

NEGX tells SPLash! that the index register X may contain negative values. NONEGX tell SPLash! that the index register will never have a negative value in it. NONEGX saves one instruction every time an array is indexed with a 16-bit signed integer.

If NEVERLIST is true, then listing lines are suppressed regardless of the setting of LIST.

The NEWDLDB feature, which is initially deselected, tells SPLash! to use the "new" model for DB-negative addressing. In the default mode (the original implementation), DL-DB addresses are located below DB (or, below register R4), just as in the Classic HP3000. With the default (NONEWDLDB), SPLash! had problems correctly addressing positive byte addresses above 32767, because sign extension was being done unconditionally, making such byte addresses appear to be negative. (The Classic HP3000 compares byte addresses to (S-DB) * 2 and then decides if the address should be considered as negative or as positive.)

The NEWDLDB addressing model places negative addresses at their unsigned equivalent address. In other words, half-word address -1 would be at 32767, -2 would be at 32766, etc. Byte address -1 would be at byte 65535, -2 would be at 65534, -40000 would be at 25536, and byte address -65536 would be at 0. Thus, no sign extension or tricky code is necessary to convert DB-relative byte addresses to 32-bit virtual addresses. SPLash! simply adds the 16-bit value to R4. For half-word addresses, the bottom 15 bits are multiplied by 2 and added to R4.

NEWDLDB solves the problem of accessing bytes with addresses above 32767, but at the cost of introducing a problem with programs that do strange address comparisons. With NONEWDLDB, a negative byte address will compare LESS than a positive DB byte address. With NEWDLDB, the comparison will be the opposite. Using NONEWDLDB, a user could count on being able to SCAN a byte address that was below DB and eventually encounter DB+0 (and the positive addresses). With NEWDLDB, the same code would scan off the end of the SPLash! stack and never hit DB+0.

If a program has a large stack and is compiled with the DL=# directive, where "#" is not 0, then NEWDLDB may provide the key to a successful program.

When NMPCAL is selected, all calls to native-mode procedures are done with efficient in-line code. When NMPCAL is deselected (i.e. NONMPCAL), calls to native-mode procedures are done by pushing the parameters onto the splash-stack and then jumping to a STUB procedure which pulls the parameters off the splash-stack and puts them into registers and/or the "native" stack, as per the procedure calling convention.

Tells SPLash! to name the outer block "main", instead of "PROGRAM" and "_start". This option is used for linking with libcinit.lib.sys or libc.lib.sys or their posix equivalents.

Tells SPLash! that a $SUBPROGRAM compilation is going to declare global variables. Since you may combine multiple $SUBPROGRAM compilations in a single XL or program, you need to specify a unique name for each OBVARS="obname".

OLDREALS tells SPLash! that all floating point arithmetic and values are in HP3000 format, not IEEE format. NOOLDREALS tells SPLash! that all floating point arithmetic is to be done in IEEE format.

[NO]OLDREALS can be specified at anytime in the source, but must be at the beginning of the statement.

OPTMOVE causes SPLash! to emit extra code for most MOVE statements in an effort to optimize the move. At present, the optimization occurs only when the source and destination are both 16-bit aligned, the move length is positive, and the move length is even. The cost is an extra 10 instructions, of which at worst 3 will be executed on a move that will not be optimized.

OVERFLOW is maintained in register R9. Bit 30 is used to remember OVERFLOW.

When OVERLFOW = IGNORE, the SPLash! compiler ignores an overflow situation that may result from arithmetic operations. The status of the overflow bit is undefined. Using OVERFLOW = IGNORE saves several instructions whenever OVERFLOW is checked. So, using other OVERFLOW options is recommended only when checking OVERFLOW is really necessary.

When OVERFLOW = TRAP, the SPLash! compiler emits code for every arithmetic operation that will result in a trap invocation whenever an overflow situation occurs.

When OVERFLOW = DETECT, the SPLash! compiler sets or resets the overflow bit depending on the outcome or arithmetic operation and type transfer functions.

When OVERFLOW = TEST, the SPLash! compiler emits code that invokes an arithmetic trap or sets or resets the overflow bit after every arithmetic operation or transfer function.

$PAGE ["text"]  
As in SPL.

PASCALIDS tells SPLash! that the underscore ( _ ) is a legal character for identifiers. With PASCALIDS, underscores may appear in an identifier anywhere an apostrophe would have been legal, including the first character position. With NOPASCALIDS, the underscore is a synonym for the assignment operator (:=).

Tells SPLash! to replace the embedded primes (') in intrinsic names with underscores (_) before searching intrinsic files.

This obscure SPL option is ignored.

SPLash! supports POP, a compiler option like the Pascal/iX $POP$. SPLash! maintains a 16-deep stack of compiler options. $POP restores the dollar options from their saved values on the stack.

In the following example, $PUSH and $POP are used to temporarily select the option "FASTMOVE" for one statement, and then restore it to the previous value:

If PP is true at the end of compilation, then the original source code (after expanding defines) is "pretty-printed" to SPLLIST (list file).

Tells SPLash! to generate C code. The PPC option compiles output with a C compiler and compiles Splash.C, and then links the data together.

Tells SPLash! to expand intrinsic declarations into equivalent external procedure declarations. Used with $PPC.

Converts 64 bit pointers to 32 bit pointers.

The effect of this option is that every procedure, entry point, subroutine and the outer block (if any) in a given compilation is marked as "PRIV_LEV 2". Note that if such an outer block is linked with the LINKEDIT option of "PRIV_LEV=3", then this will override the SPLash! attempt to mark the outer block as privileged.

If the PSTRINGS (Pascal strings) option is enabled, a single control character can be appended at the end of a string constant. The following examples illustrate.  

For example, move msg:="hello world"#13#10; .

SPLash! supports PUSH, a compiler option like the Pascal/iX $PUSH$. SPLash! maintains a 16-deep stack of compiler options. $PUSH pushes the current setting of all on/off compiler options onto the stack (e.g., LIST, NATIVE, MAP, MILLIMOVE).

In the following example, $PUSH and $POP are used to temporarily set the option "FASTMOVE" to true for one statement, and then restore it to whatever the old value was:

The QUICK option tells SPLash! to emit a shorter (and faster) code sequence for calling splash-mode procedures. This sequence still builds a four-word stack marker, but does NOT save the X-register or pass back the condition code (or status register) at procedure exit time.

Tell SPLash! to use registers (if available) for simple variable storage. Note that SPLash! cannot pass REG variables by reference. For example:  

        integer  FOO = REG;

Warns if both sides of an assignment are the same size, even though they are different types. Also warns if a value parameter type mismatch occurs (e.g. passing a double to a real by value).


$SEGMENT = segmentname  
This option is used to direct what locality set the procedures that follow are to be placed in. The effect of SEGMENT in SPLash! matches that of SPL. For example,  $segment=code .

$SET X# = {ON, OFF}  
As in SPL. X# is one of: X0, X1, X2, ..., X9.

SOURCE requests a listing of all source records. NOSOURCE suppresses a listing of source text.

If SPLASH is true, then this is equivalent to:

Otherwise, it is equivalent to:

Using NOSPLASHG tells SPLash! not to use the SPLASHG.PUB.SYS file.

If SPLASHEXT is true, certain SPLash! extensions are enabled. These include allowing single precision integer constants to be used where double precision would normally be expected, and 32-bit constructed constants.

This dollar option tells SPLash! what mode a procedure declared in a user intrinsic file (of the SPLINTR-format) should be (OPTION NATIVE or OPTION SPLASH).

Warning #341 is generated whenever a SPLINTR-format user intrinsic file is opened and NOSPLASHINTRINS is in effect.

Warning #342 is generated whenever a SPLINTR-format user intrinsic file is opened and SPLASHINTRINS is in effect.

$STACK = #  
(Option may be deleted in future release)

The STACK option tells SPLash! how much extra space native-mode procedures should allocate on the native mode stack for temporary values. At present, STACK defaults to about 400 bytes. The largest value seen during a compilation will be remembered and used.

If STATISTICS is selected at the end of compilation, internal compiler statistics will be displayed.

If STMT is true at the end of compilation, then the assembler code generated will include "statement numbers" in a format that the MPE/iX debugger recognizes.

This option will degrade system performance somewhat, but it yields much better debugging information.

SUBPROGRAM tells SPLash! that this compilation does not have an outer block and is destined to either be called from non-SPLash! NM languages or to be linked into a SPLash! outer block.

SPLash! does not support the SUBPROGRAM (...) form of SPL.

If no SPLASH, NATIVE, or EXTERNAL control card has been seen prior to the SUBPROGRAM card, then an implicit EXTERNAL=NATIVE is issued.

If no SPLASH, NATIVE, or INTERNAL control card has been seen prior to the SUBPROGRAM card, then an implicit INTERNAL=NATIVE is issued.

See the chapter on separate compilation for more information.

If SUBRNAMES is true at the end of compilation, then all subroutines will have a name of the format:

This will cause the MPE/iX debugger to display the subroutine name as:

Breakpoints can be set in subroutines in this case by doing:

The SUPPRESS/NOSUPPRESS option allows specific warning messages to be suppressed. Warning #5 defaults to "suppressed", all others default to "not suppressed". A complete list of warning messages is found in message set 2 of the file SPLCAT.PUB.SPLASH .

This option is used to change the number of significant characters in a variable. The default value is 15. The maximum value that can be assigned is 31.

NOSYSINTR tells SPLash! to use SPLINTRX.PUB.SPLASH instead of SYSINTR.PUB.SYS as the default intrinsic file. Only the native-mode version of the SPLash! compiler can read SYSINTR format intrinsic files. The CM/OCT version cannot.

TESTSP uses register 25 to pass a desired new SP value to the SPLash_checksp millicode routine.

This obscure SPL is ignored.

This obscure SPL is ignored.

$TITLE ["text"]  
As in SPL.

This option is ignored.

TRACEPCAL does not generate ANY extra code, it merely emits extra assembler directives. This makes it possible to trace through SPLash! procedures, subroutines, and stubs. A possible exception is if the procedure has virtual arrays. These produce dynamically-sized native mode stack frames, which are difficult to debug.

TRY supports TRY-RECOVER actions. When it is selected, the words TRY, RECOVER, ESCAPE and ESCAPECODE become reserved keywords. See the section on run time error recovery for details.

This obscure SPL is ignored.

This obscure SPL option is ignored.

Use this control option when you want to generate Assembly language code for the HP-UX platform. This option tells SPLash! to use the appropriate Assembler directives for execution on HP-UX. It also instructs SPLash! to set up the Q register for programmatic access to argc, argv, and envp as follows:

See the section "Porting to HP-UX" for more information about migrating to HP-UX using SPLash!.

This option controls the case of the external names for intrinsics declared after the option is detected. If it is selected, then the intrinsics are assumed to have uppercase external names.

Tells SPLash! that intrinsic file procedure names in the SYSINTR- format should be upshifted to uppercase.

This option is quietly ignored (irrelevant for native mode programs on MPE/iX).

This option overrides the normal SPLash! treatment of procedures declared in user intrinsic files as "variable". By default, SPLash! allows parameters for such procedures to be omitted (default equals 0), but no parameter mask is passed. This default value was selected because it comes closest to matching Pascal/iX needs.

However, certain user intrinsic files with procedures written in SPLash! need to be "option variable", complete with the parameter mask at Q-4. These files can take advantage of this option instructing SPLash! to pass the parameter mask even though the procedure is an "intrinsic". The following code fragment provides an example.

$VERSION ["text"]  
VERSION "text.......text" is nearly identical to $COPYRIGHT, but all of the text is emitted via ".VERSION" assembler directives.

This dollar option tells SPLash! that all ARRAYs and POINTERs declared in the outer block as "GLOBAL [type] ARRAY" or "GLOBAL [type] POINTER" are to be automatically considered as "GLOBAL VIRTUAL [type] ARRAY" and as "GLOBAL VIRTUAL [type] POINTER".

As in SPL.

$X# = {ON, OFF}  
SPLash! has ten compiler flags (X0, X1, X2, ..., X9) which can be assigned the values of ON or OFF. The IF option uses these variables to optionally skip compilation of a sequence of source code statements. Note that X9 is typically set to indicate whether or not it is a NM compilation. See SETX9.INC.SPLASH for more information.


Instructs SPLash! to provide procedure and variable cross-reference information in the list file.

The following chart lists each option, it's default value, and notes whether it is oriented towards optimizing performance, testing program operation or if it is a SPLash! only feature.

(top) (index)

$Option Default & Function Chart

Add the following external declarations to your program. Or, include the file SETJMP.EXT.SPLASH .

Logical Procedure splash'setjmp(jumpinfo'd)

Calling this procedure saves state information in jumpinfo'd for use by the splash'longjmp procedure. The return value is zero for a direct call to splash'setjmp (i.e., when arming it) and non-zero from a subsequent call to splash'longjmp.

Procedure splash'longjmp(jumpinfo'd,rslt)

Calling splash'longjmp restores the state saved by the last call to splash'setjmp using jumpinfo'd. Execution resumes as if the splash'setjmp procedure had just executed and returned the non-zero `rslt'.

Linking the Procedures

After compiling your program with SPLash!, you will need to link with the JUMPERO.MILLI.SPLASH file.

For example:

(top) (index)

7   Using XREF


XREF is an SPL cross-reference tool that reports on variables, procedures, intrinsics and external calls located in your program. It will note where the variables are declared; where procedures, intrinsics, and external calls are called; and where variables are changed or accessed. XREF also reports on variables that are declared, but never used. This kind of information can be valuable for identifying potential problems or as a general quality assurance mechanism.

Operationally, XREF reads an SPL program specified by the infile equation text and then sends the cross-reference listing to a file called LIST in the logon group.

Various PARM options can be selected by setting PARM options in the RUN statement; using the Bit# chart provided, you can combine the decimal values of two or more bits to select those specifications that are useful to you.


The chart below lists the Bit#, the corresponding action for that bit, and its decimal value. The decimal value is useful for specifying command combinations. The example section shows exactly how this is done.

   Bit#    Action    Decimal
   09    Print only UNUSED items     64

   10    Suppress report of Lowlevel statements ( ASSEMBLE, SET, PUSH, ABSOLUTE)    32

   11    Report usage of TOS     16

   12    Print report of unused items generated from $INCLUDE files (normally suppressed)    8

   13    Suppress report of UNUSED items     4

   14    Ignore $IF cards    2

   15    Read INCLUDE files    1

XREF Examples

Specifying a Single Parameter

To run XREF on a source file and its $INCLUDE files, you would need to specify bit 15 which reads INCLUDE files. The number in the far right column is the value to assign to the parm variable. For example:

Specifying Multiple Parameters

To run XREF on a source file and its $INCLUDE files and only report on unused items, sum the values in the far right column for bit 15 and for bit 9. For example:

The parm setting is the sum of the decimal settings for bit 15 which has a decimal value of 1 and bit 9 which has a decimal value of 64.

Sample Output

:file text=ascii.inc.splash
:run xref.pub.splash

Reading source file... S.P.L. Cross Reference -- Sep 27, 1990 SS:90.1

* Indicates a modified reference # Indicates a reference found by expanding a DEFINE > Indicates a reference found in an INCLUDE file


TUE, JUN 4, 1991, 4:26 PM

#Cards: 110, #Symbols: 14, #References: 76, #DEFINEs: 0

BASE (Undefined Label) 49 49 *51 55 73 97 117

HEXIT (LOGICAL ARRAY) 31.1 121 122 123 124


LENGTH (INTEGER) 26 *87 90 92 *108 *109 *110 *111 *112 *113 *126 *127 *128 *129






STR' (Undefined Label) *90 90 *92 *101 *102 *103 *104 *105 *106 108 109 110 111 112 *121 *122 *123 *124 126 127 128


TEMP' (BYTE ARRAY) 39 *62 *75 *81 90 92 *134

WORD (INTEGER) 27 58 60 *66 66 70 99 119

XREG (INTEGER) 28 *63 *71 75 *81 81 87 92 110 111 112 128




(top) (index)

8   Migration Issues


The sections in this chapter address the topics that experience has shown to be common issues for users migrating programs to the HPPA platform. These topics include suggestions on how to deal with Control-y trap handlers, format differences between Classic and Spectrum real numbers, and the data types supported by SPLash!. A short section on how SPLash! can be used to port SPL programs to HP-UX concludes the chapter.


SPLash! users who are porting code that uses Control-Y will be forced to make some code changes. In most cases these coding modifications will be small, perhaps only the addition of one or two lines of compiler directives.

Unless told otherwise, SPLash! assumes that mainline source modules are intended to be compiled in SPLASH mode. SPLASH mode emulates the classical architecture's parameter passing and stack. However, with the new machine come new protocols for procedure calls. SPLash! is able to simulate the correct calling sequence protocol for calling NATIVE procedures from OPTION SPLASH procedures. However, it is not possible for operating system procedures to call OPTION SPLASH calls because the operating system does not know to use the classical protocol.

Since the operating system doesn't know about SPLash!'s classical protocol, trap handling procedures cannot be compiled using OPTION SPLASH.

The solution to the problem is to make trap handling procedures OPTION NATIVE, which will solve this problem in most cases. However, simply making this change may create an even larger problem. All procedures that the Control-Y trap handler calls must also be compiled OPTION NATIVE.

If there are only a few procedures which are called exclusively by the Control-Y trap handler, then these can be made OPTION NATIVE. Unfortunately, if the number of procedures is extensive, or if they do 16-bit address manipulation, then you may be faced with a major amount of work.

On MPE V, a Control-Y handler returns by building an EXIT instruction on the top of stack and then executes it. However, this is not necessary on MPE/iX because the operating system adjusts the stack when the procedure exits. Therefore, simply exiting an OPTION NATIVE Control-Y handler will return the program to its normal flow. So, whenever SPLash! sees an XEQ 0, it assumes that it is the exit code for a trap handling procedure. SPLash! will print a warning message stating that XEQ 0 will be treated as an exit. You may eventually decide to remove the ASSEMBLE (XEQ 0) from your code.

The following is an example which shows how a Control-Y trap handler can be converted.

    begin   ! SPL

    procedure do'control'y'stuff; begin . . . ! Standalone code (No calls to SPLASH procedures) end;

    procedure controly; begin

    integer sdec = Q + 1;

    do'control'y'stuff; tos := %31400 + sdec; ! Building an EXIT instruction. assemble (XEQ 0);

    end <<controly proc>>;

A possible change for MPE/iX would be:

    procedure do'control'y'stuff;
       option native;
            ! SPLASH -> NATIVE is okay, but NATIVE -> SPLASH isn't.
            ! The "controly" procedure is being converted to NATIVE
            ! so this one needs to be NATIVE as well. If this procedure
            ! called other procedures, those would need to be NATIVE too.
    . . . ! Standalone code (No calls to SPLASH procedures)

    procedure controly; option native; ! When Control-Y is pushed, execution is transferred to the ! Operating System. The Operating System then makes a ! call to this procedure using the NATIVE procedure protocol. begin

    do'control'y'stuff; return; ! Remove XEQ 0 and go to procedures end



Floating Point Format

An important issue that typically arises in a migration involves the floating point formats used by the MPE V based and MPE/iX based machines. HP decided early in the Spectrum project to standardize the format used to store and process floating point numbers, and the IEEE standard for floating point was adopted. Developing the means for format conversions is the topic of this section.

IEEE Reals & Classic Reals

Most floating point formats share several characteristics. First and foremost is that the number is stored in two parts, called the `mantissa' and the `exponent'. This can best be seen by using the scientific notation convention to express real numbers. For example, the number 4324.00 is expressed as 4.324 * 10 ** 3. Scientific notation always expresses the number as a mantissa between 1 and 9 with some number of decimal places multiplied by an exponent, which is 10 raised to some power. In the example, 4.324 is the mantissa and 3 is the exponent. Numbers less than 1 are expressed with negative exponents, indicating that the decimal place is shifted to the left instead of the right. In this case, the number .02334 would be expressed as 2.334 * 10 ** -2.

Second, an entire number can be negative, so a sign is associated with the mantissa. For any real (floating point) number format to be useful, the mantissa, exponent, and their associated signs must be stored.

Some adjustments are made in the number format to make the storage and manipulation easier in the computer. Typically, the first bit (from left to right) is the mantissa's sign bit. Unlike integer numbers, real numbers are not stored in two's complement format. The sign bit is a simple binary 1 or 0 to indicate whether or not the number is negative. Next usually comes the exponent. Instead of storing this number in the usual two's complement, the number is biased to a certain base value. Biasing involves adding some constant (always the absolute value of the largest negative exponent) to the real number. For example, if the exponent is biased by 127 and the exponent value is 0, the number stored as the exponent is 127. If the exponent is -45, the number 82 is stored, and an exponent of 54 will cause the number 181 to be stored.

What this accomplishes is to simplify comparison of real numbers. With the exponent stored as the leading bits in the storage area and properly biased, a simple byte comparison can determine the inequality of two numbers.

The mantissa is stored as an absolute value, since its sign is the leading digit of the real number. The other main difference in real number formats is the total number of bits used for storage and the number of bits assigned to the mantissa and the exponent.

The HP3000 stores real numbers in single precision (32 bits) or double precision (64 bits). Single precision uses 9 bits for the exponent and 22 bits for the mantissa. The IEEE standard also defines a short (32 bits) and a long (64 bits) format, and further defines a 128-bit format called a `quad real'. The IEEE format defines a single precision number to contain 8 bits for the exponent and 32 bits for the mantissa.

While the difference is small, it affects the size of the numbers that can be stored. Further, the IEEE standard defines the way error, exception, and trap handling are to be done to a very exact level. The HP3000 format does not, and the exception handling is defined by the microcode which performs the various floating point operations. On MPE/iX, all IEEE floating point operations are performed by the floating point coprocessor. If one does not exist, the hardware traps to software routines, which simulate the execution of this piece of hardware. MPE/iX uses software to perform HP3000 format floating point operations.

The floating point format can be a problem in migration if the format is used extensively in disc files and data bases. Two options exist for converting floating point code:

If your application uses floating point heavily, consider converting the data. TurboIMAGE and QUERY assume all real numbers are in HP3000 floating point format. This must be taken into account if NM languages are to access data bases.

The table below notes the differences between classic HP3000 and IEEE real formats.


Classic HP3000 floating point has been implemented, for both 32 and 64-bit reals ("REAL" and "LONG"). At present, a given program or subprogram compilation may contain only one type of reals. It is possible, however, to combine several subprograms containing both types of reals, as shown in the following example. Note that the default is to use IEEE floating point.

The example shows how code might be written to fetch two 32-bit real numbers from a record in an IMAGE dataset, and then use either IEEE or Classic floating point arithmetic on the values, and then write the sum back to the dataset. It is only a fragment of code and leaves open the question of how the logical variable "using'ieee" got its value...that's up to you!

Source file SUB1:

Source file SUB2:
Source file OB:


    ... real procedure add'classic (r1, r2); value r1, r2; real r1, r2; option external, native, nocc;

    real procedure add'ieee (r1, r2); value r1, r2; real r1, r2; option external, native, nocc;

    ... dbget (.... buffer ...); ... x := buffer'oldsalary; y := buffer'wageincrease; ... if using'ieee then buffer'newsalary := add'ieee (x, y) else buffer'newsalary := add'classic (x, y); ... dbupdate (...buffer...); ... end.

SUB1, SUB2, and OB are each separately compiled with SPLash!, assembled, and their corresponding object files are saved as (perhaps) SUB1.OBJ, SUB2.OBJ, and OB.OBJ. Then, the link command combines them into a single program, OB.PUB. For Example:

(top) (index)

Data Types & Equivalents

This section describes the data types supported by SPLash!, and their equivalences in other native mode languages.

The base SPLash! data types are:

8 bits. A byte can be thought of as holding an ASCII character or a numeric value in the range 0..255.

16 bits. A logical is a numeric value in the range 0..65535. Logicals are often used for boolean arithmetic. The constant "true" is a logical value with all bits turned on (65535, or the integer value -1). The constant "false" is a logical value with all bits turned off (0).

16 bits. An integer is a numeric value in the range -32768..32767.

32 bits. A double is a numeric value in the range -2147483648..2147483647.

32 bits. A real is a single precision floating point number. Depending on the compiler flag OLDREALS, a real represents either an IEEE value or a Classic HP3000 value.

64 bits. A long is a double precision floating point number. Depending on the compiler flag OLDREALS, a real represents either an IEEE value or a Classic HP3000 value.

SPL and SPLash! allow integers, logicals, and bytes to be stored into each other with no warnings, conversions, or range checking. Within expressions, integers/bytes/logicals can be type-coerced into any of integer/byte/logical.

For storage compatibility, SPL and SPLash! require primarily that the left and right sides of the ":=" have the same number of bits. A byte variable is treated as though it were 16 bits in size, allowing byte:=integer, and integer:=byte. This requirement means that it is legal to assign a real to a double, and vice versa. SPL and SPLash! do not generate warnings OR conversion code when this is done.

Parameter passing has the same compatibility requirements as the assignment statement.

(top) (index)

Using Other Languages

This table maps data types between SPLash!, Pascal/iX, and C/iX. Some types map exactly. For inexact maps, equivalent SPLash! (or Pascal/iX) datatypes are suggested.

No mappings known:

1 SPL and SPLash ! allow only single dimensioned arrays.

2 Pascal/iX may not result in a 16-bit variable, "integer" may be a better equivalent.

3 When Pascal/iX passes a longint or a longreal by value, it really passes the address of a copy of the data. A longint is a 64-bit integer, a longreal is a 128 bit real.

4 The SPLash! "pointer" data type assumes either a "virtual pointer" or an ordinary pointer within a Native-mode procedure. Such pointers, like the "^" pointers in Pascal/iX, are 32 bits in size. An ordinary pointer in a splash-mode procedure would be 16 bits in size and cannot be passed by reference to a Native-mode procedure.

5 A "label" in SPLash! can be passed into a procedure as a parameter. It currently takes 48 bits on the stack, just as in SPL.

6 A "byte" variable passed by value to a procedure is handled specially in SPL and SPLash !. In and in SPLash! splash-mode procedures, the 8 bits of data is found in the UPPER 8 bits of a 16-bit halfword. In SPLash!, Native-mode procedures and in all other native mode languages, the 8 bits of data is found in the lower 8 bits of a (typically) 32-bit word.

In addition to data type differences, the programmer should be aware of the ways a parameter can be passed to a procedure within Pascal/iX, and their reflections in SPLash! Pascal/iX allows parameters to be passed: (1) by value; (2) by "var"; (3) by "anyvar"; (4) by "readonly"; and (5) by "uncheckable anyvar".

The following describes how to pass SPLash! data into Pascal/iX procedures using each of the four methods.

The programmer should be aware that Pascal/iX never truly passes by value data that is bigger than 64 bits. Instead, a copy of the data is made and the address of the copy is passed. Thus, for all simple variables (except longint and longreal), simply declaring them as "value" in SPLash! suffices. Larger variables (or records) must be declared in the external-declaration as being passed by reference.

"var" is by reference, where the address passed is a 32-bit short pointer. Simply declaring the parameters to be reference in SPLash! suffices. (Remember: reference is the default in SPL and SPLash! if the "value" statement is not used.)

"anyvar" is a variation on the "var" mechanism. In addition to passing the address of the variable, a hidden following parameter is passed which tells the size of the actual parameter in bytes. At present, SPLash! does not support "anyvar". As a workaround, TWO formal parameters should be declared: first, the reference parameter; second, a double by value. When the procedure is called, the double by value should be given the size (in bytes) of the first parameter.

"readonly" is identical to "var" and tells Pascal/iX that the programmer will not be changing the data. Simply declaring the parameters to be reference in SPLash! suffices.

"uncheckable anyvar"  
This is another variation on "var". From the SPLash!'s viewpoint, it should be treated as a "var".

At present, SPLash! will not correctly pass a pointer variable to a parameter that is marked "uncheckable anyvar" or "anyvar" unless the formal parameter is also a pointer. This restriction makes it necessary to fool the compiler when calling intrinsics that expect arbitrary parameters, some of which may be pointers by reference. The only example of this kind of intrinsic, at present, is HPFOPEN. If the programmer wants to use item # 21, which requests that a fullvirtual pointer be passed back, the following calling sequence would not work in the current version:

In the above call, SPLash! would try to pass the VALUE in ptr instead of the address of ptr. A workaround is:

(top) (index)

Porting to HP-UX

This section explains how you can use SPLash! to port SPL programs to the HP-UX platform. The steps involved in using SPLash! to port SPL programs to HP-UX are different than when you port to MPE/iX. Because SPLash! doesn't run on the HP9000, only the first part of the compilation process is done on the HP3000, translating the SPL into HPPA assembly language. Then, the assembly language file is transferred to the HP9000 where it is assembled and linked to create an HP9000 executable program. Once this is accomplished, you then need to provide replacement calls for all of the HP3000 intrinsics used in your application by using any of the several methods outlined in this section.

These replacement methods are discussed next.

(top) (index)

Method I. Intrinsic Intercept

This approach involves replacing HP3000 intrinsic declarations with functionally equivalent C or Pascal code on the HP9000. In your SPL program, include external declarations (instead of intrinsic declarations) for any HP3000 intrinsics that your program uses. Then, on the HP9000 intercept the external calls and replace them with C or Pascal functional equivalents.

Step 1: Include the following declarations in the SPL source

$set x8=on ! Denotes HP-UX compilation $native $if x8=on $unix $endif

begin byte array msg(0:79); integer i;

$if x8=off intrinsic print; $else procedure print(buffer,len,cctl); value len,cctl; integer len,cctl; byte array buffer; option external, native, uppercase; $endif

i := move msg := (13,10,"Hello world"); print (msg, -i, 0);


Step 2: Compile the SPL on the HP3000 to create HPPA Assembly Language

! compile with SPLash, then transfer hello.asm to the HP9000 SPLXL hello, hello.asm, $null

Step 3: Intercept Intrinsic calls on the HP9000 using the C Intercept Library

        ! assemble
                as hello.asm hello.o
        ! compile C intercept library
                cc -Aa -c mpeint.c mpeint.o
        ! link into executable
                ld /lib/crt0.o hello.o mpeint.o -ohello.exe

! hello.exe is the ported SPL!

The C Intercept Library

The C intercept library and its associated files can be found in the SPLASH account. This intercept library contains C code for many commonly used HP3000 intrinsics. As it stands today, the intercept library is not exhaustive. Over time, however, it will eventually evolve into a complete, comprehensive library that provides equivalent intrinsic functionality for all HP3000 intrinsics for which a C equivalent can be created.

The following files are provided to assist in intercepting HP3000 intrinsics:

MPEINT.EXT Include this file in your SPL source, it contains external declarations for several HP3000 intrinsics.

        $if x8=on

begin ... $if x8=off intrinsic print, quit, ... $else $include mpeint.ext.splash ! external declarations $endif
To compile... :SPLXL source,,$null info="x8=on"

MPEINT.H Header file for MPEINT.C

FSERR.H Include file for MPEINT.C

SSTYPES.H Include file for MPEINT.C

MPEINT.C C source code. Contains intercept routines for all of the external declarations in MPEINT.EXT, plus several other general purpose functions. These functions are discussed next.

C Functions

The file MPEINT.C contains the following intrinsic intercept functions:

Plus, the following general purpose functions:

The general purpose functions are used internally (by the intercept functions). If you write additional intercept functions you will probably need to use them as well.

In several cases, a simple C library function that can be used to replace an intrinsic call may not exist. In this case, you will be required to follow a port path of Intrinsic Replacement.

(top) (index)

Method II. Intrinsic Replacement

The Intrinsic Replacement method is, as its name suggests, a porting approach that involves replacing HP3000 intrinsic calls with calls into the C or Pascal libraries. This approach to porting is more coding intensive than the previous approach. But, because HP has both a C and Pascal compiler available on both systems (HP3000 & HP9000), porting and testing can be performed to a large degree on the HP3000 and then transferred to the HP9000 for final development & testing.

When you use this approach, the C or Pascal replacement code should be constructed as subprograms and then linked with the NMOBJ file produced during the assembly phase of the SPLash! compilation.

Successful porting of a SPL program through this method will result in a SPL source with very little dependence on the environment in which it is run.

Method III. Code Replacement

An SPL to C translator is being actively developed as an extension to the SPLash! compiler. No release date has been announced. This will probably be a several pass process where the SPLash! compiler is the front end, followed by several processor passes until usable C code is produced. Call Allegro if you are interested in more information on this methodology.

(top) (index)

9   Run Time Error Recovery


SPLash! run time error recovery includes intrinsic-based trap support and TRY-RECOVER blocks. These methods are discussed next.

Intrinsic Traps

The following intrinsics provide trap support for run time error recovery: XLIBTRAP, XARITRAP, and XCODETRAP. See the MPE/iX intrinsics manual for an explanation of how these work.

(top) (index)


SPLash! supports TRY-RECOVER blocks used for building efficient run time error handling into an application.

The TRY-RECOVER block begins with the keyword TRY. Following the TRY keyword can be any valid SPL statements. If a run time error occurs after a TRY statement has been encountered, control is passed to the associated RECOVER block. Syntactically associated TRY and RECOVER statements must reside in the same SPL procedure. TRY-RECOVER blocks can be nested, however.

For example:

Using TRY-RECOVER Programmatically

To use a TRY-RECOVER block in your program, include the control statement $TRY at the beginning of your source module. $NOTRY is the default.

When $TRY is active, the words TRY, RECOVER, ESCAPE, and ESCAPECODE become reserved keywords and can only be used in the context of a TRY-RECOVER block.

TRY-RECOVER Components

The components of a TRY-RECOVER block include the ESCAPE procedure, the ESCAPECODE function, and the TRY-RECOVER block.

ESCAPE Procedure
This is a system procedure that gets control when a run time error occurs or when called directly by your program. This procedure accepts a 32-bit integer (double in SPL) as its only parameter. This parameter is the error code that will be passed to the RECOVER block via the ESCAPECODE function. In the event of a run time error, the parameter is set by the operating system. Otherwise, your program will provide the value for the parameter. Note —If a run time error or escape are executed outside of a TRY-RECOVER block, the program will abort.

This system function returns the last error code that was passed to the ESCAPE procedure. The error code is a 32-bit integer (double in SPL). See the section "System Escape Codes" that follows for a list of predefined system escape codes.

The TRY-RECOVER Block Structure
The general form of the try-recover block is:

The TRY keyword defines the beginning of the TRY-RECOVER block. Any run time errors or calls to escape from within this section will result in program control being passed to the RECOVER block. The TRY section can contain any valid SPL statements including compound statements, procedure calls, and TRY-RECOVER blocks. Note —The TRY-RECOVER mechanism is implemented like a stack. The last TRY-RECOVER block will be the first one called when an escape call is made.

The RECOVER keyword defines the beginning of the RECOVER block. This is the section of code that gets control when an escape is executed. Like the TRY section, the RECOVER section can contain any valid SPL statements including compound statements and other TRY-RECOVER blocks. Note —If a run time error or escape is executed within a RECOVER block, this will result in a program abort unless the current TRY-RECOVER block is contained within another TRY-RECOVER block.


The following list can be found in SYSESC.INC.SPLASH , which is a subset of the information from PASESC.PUB.SYS (provided by HP):

(top) (index)

Appendix A : <TT>ASSEMBLE</TT>

Assembler Instructions

This section describes various forms of the SPLash! ASSEMBLE statement and offers instructions on usage for native mode, compatibility mode and privileged operations.

P-relative Addressing

Currently, P-relative addressing within ASSEMBLE statements is not supported. Historically, this feature was used for three reasons:

1. An assemble (BCY * +1) cleared the carry bit. SPLash! provides a new opcode, CLCY, which has the same effect.

2. It offered the ability to define conversions from byte addresses to word addresses and vice versa. SPLash! provides the BTOW and WTOB opcodes as a replacement.

3. It was "neat" to code large ASSEMBLE statements with P-relative branching. SPLash!, as does SPL, allows labels within ASSEMBLE statements, which replaces most of the need for this type of branching.

CON pseudo-op

The CON pseudo-op of the ASSEMBLE statement is also not supported. CON was historically used in SPL programs for two purposes:

1. It provided a method for assembling instructions added to the HP3000 after the SPL compiler had been written. These instructions did not have opcode mnemonics recognizable to the compiler. SPLash! provides mnemonics for these instructions (e.g. TRDB, TRPB, EADD).

2. It provided a way "drop" constants (numeric or string) into the code. This objective can be achieved through PB-relative arrays which provide identical functionality coupled with better readability.

HPPA Instructions

The following HPPA assembler instructions have been implemented and are available through the ASSEMBLE statement.

PROBER Determines whether read access to a given address is allowed.
Usage: assemble (PROBER (sr#, gr#), gr#, gr#);  

PROBEW Determines whether write access to a given address is allowed.
Usage: assemble (PROBEW (sr#, gr#), gr#, gr#);  

MTSP Moves a value from a general register to a space register.
Usage: assemble (MTSP gr#, sr#);  

MFSP Moves a value to a general register from a space register.
Usage: assemble (MFSP sr#, gr#);  

RSYSG Reads a 32-bit value from the system globals area.
Usage: assemble (RSYSG #);

The # parameter (which must be a multiple of 4 in the range -8192..8191), is used as a byte offset from the base of the system globals area ($c0000000). A 32-bit word is fetched from this address. This 32-bit word is pushed onto the stack.

For example, in MPE XL 1.1, system globals + $DEC contains the "real_memory_size", which can be obtained through either of the following statements:

MFVA / MTVA Move from/to virtual memory and the stack. These instructions expect a 16-bit DB relative address, a 32-bit virtual address, and a number of bytes to be moved.  

KSO Known System Object.
Usage: assemble (KSO #)

The 8 byte Known System Object (KSO) specified (#) is fetched and pushed onto the stack, with the space ID at S-3/S-2, and the offset portion at S-1/S-0. An example of using this opcode to quickly fetch the value of KSO 9 is:

If only the bottom 32 bits are desired, the KSO opcode can be used:

Classic instructions

The following assembler instructions are also available.

SCAL Subroutine call.
Usage: assemble (scal 0);

This opcode will pop a 32-bit code address from the stack, and then branch to it, leaving the return address in register R2 (just like a regular subroutine call.)  

BOV Branch on overflow.  

BNOV Branch on no overflow.  

TRDB/TRPB Implement the two flavors of the TR opcode, which translates byes via a DB-relative or a PB-relative table.  

CLCY Clears the CARRY flag (higher level than: BCY *+1). An ASSEMBLE (BCY *+1) cleared the carry bit. SPLash! provides a new opcode, CLCY, which has the same affect.  

CLOV Clears the OVERFLOW flag.  

BTOW Convert 16-bit byte address to 16-bit word address.  

WTOB Convert 16-bit word address to 16-bit byte address.

Converts a 16-bit stacked byte address to a 16-bit word address, (and vice versa) taking into account the problems of byte addressing on the classic HP 3000 (i.e., if a byte address appears negative, is it below DB, or merely a large positive address?).

Privileged instructions

In MPE V/E "low" memory is referred to as "bank 0". This bank of 128KB contains many interesting tables and values. PM code can access this data via the following opcodes:

In the list above; "Single" means a 16-bit value, "Double" means a 32-bit value. "Extended Address" means a 16-bit bank number and a 16-bit half-word offset within the bank. "Half-word" means a 16-bit word.

SPLash! does not attempt to compile these opcodes because most applications involve accessing system tables that may have changed from MPE V/E to MPE/iX.

If your code contains any of these opcodes, use the replacement routines located in the file MDS.INC.SPLASH . These routines provide similar functionality, and are in most cases identical in function to using the most of the above opcodes with a stack decrement value of "delete all parameters".

Note —PRIV MODE must be enabled to use these routines, otherwise an error message, instruction memory protection trap , will be generated.

MPE/iX maintains a memory area that is equivalent to the Classic HP3000's bank 0. At present, and this may change , it is found at virtual address $80000000. However, this area is only 128KB long, which means that it is equivalent to bank 0, and no other banks are simulated.

The replacement routines that have bank parameters check to be sure that you are trying to access bank 0. If a bank other than 0 is passed in, the routine will call splash_abort (found in the MDS.INC.SPLASH file). The MOVE routines do not allow negative move lengths.

In the particular case of MDS, MTDS, and MFDS, many applications of these opcodes involved implementing a fast method of moving data to or from the stack and an extra data segment. Although it is still possible to do this (via these routines), we strongly recommend recoding to use the native-mode heap or a mapped file.

(top) (index)

Appendix B : Intrinsic Changes

Intrinsic Changes

There are several intrinsics that SPLash! recognizes as potentially needing programming attention. The reasons vary; for instance, some intrinsics no longer exist, or the name may have been changed. The following list describes these intrinsics, and what has changed.


The SWITCHDB intrinsic and the undocumented EXCHANGEDB procedure do not exist in native mode. The file XDB.INC.SPLASH contains code for a splash-mode EXCHANGEDB routine. It requires linking with GETOLDDB.MILLI.SPLASH .

If a program attempts to declare SWITCHDB via an intrinsic declaration (e.g. intrinsic switchdb), it will usually generate a syntax error since SWITCHDB is not found in SYSINTR.PUB.SYS .

The file XDB.INC acts as a replacement for SWITCHDB and EXCHANGEDB.

Hint Investigate why your code is using split-stack mode. Performance will probably be improved by simply allocating a chunk of memory on the NM heap (using the P_GETHEAP or GETHEAP intrinsics).

If access to a REAL extra data segment is essential, then this routine should work for you but this has not been verified.

Note —This routine produces a SPLASH-mode procedure! If you need a Native-mode procedure, then contact Allegro. A Native-mode EXCHANGEDB is harder because it must change the saved R4 value in the stack frame.

(top) (index)

Appendix C : Compiler Messages

The SPLash! message catalog may be found in the file SPLCAT.PUB.SPLASH .

(top) (index)

Appendix D : SPLash! Debugger

SPLash! Debugger

The material presented in this section is provided only for the sake of completeness. The SPLash! Debugger is used primarily by the designers of SPLash! for troubleshooting and requires significant knowledge of the internal workings of the program to be of real value to the average SPLash! user. But feel free to explore!

Note —If the JCW SPLASHDEBUG is set to a non-zero value then SPLash! will invoke it's debugger if an assertion error occurs.

SPLash! Debugger Commands

Commands may be abbreviated to just the uppercase portion. Whenever a node number is allowed, the words: ROOT, DAD, SON, NEXT, and TAIL are also accepted.

The debugger also contains a help subsystem. Typing HELP at the DEBUG prompt will display much of the text contained in this section. The text is contained in the file SPLASHHL.PUB.SPLASH .

The SPLash! debugger commands are listed next.

Aborts SPLash! by calling QUIT.

ASK [$] [c]  
Invokes the conversational debug-flag setter. If the optional "$" is specified, then the dialog pertains only to $CONTROL flags. If "c" is specified, only options starting with that letter (or greater) will be presented. This routine will loop until a slash(/) is entered, then it will return back to the debugger. Note — If a back slash (\) is entered, the routine exits and the debugger will exit.

Back [#nodes]  
Moves the "current node" backward #nodes nodes. (Default is 1 node)

BASE [8/10/16/Octal/Hex/Integer/Decimal]  
Sets the "base" to the specified value. The initial base is 8. If no parameter follows "BASE", then the current value is reported.

BREAK procname [PERM | TEMP]  
Sets a breakpoint to enter the SPLash! debugger when the specified procedure is called. The type of breakpoint, permanent or temporary, may also be specified (the default is permanent). This option is only available when running under the MPE V operating system.

Exits the debugger, just like the slash (/) command.

Reports what the "current node" is, and whether or not it appears to be a valid node number.

DAD [#]  
Reports dad of specified node. If # is omitted, then the "current node" will be used. The dad becomes the new "current node". Thus, to print the tree for the grandfather of node 804 you could do:

Calls Debug/iX, the HP debugger.

Recursively calls the debugger with the specified text. This command exists as a means of testing the programmatic interface to the debugger (i.e., debugger (buf, len))

DEBUGNOde [node#]  
Tells SPLash! you want to enter the debugger when this node is allocated or when it is prettyprinted.  
Note —Defaults to current node.

Display [ dbaddr# ] [#words] [base]  
Displays the specified range of DB-relative addresses in the chosen base (8/10/16/Octal/Decimal/Hex). Dbaddr defaults to the prior value (initially 0). #words defaults to 40. Base defaults to the prior base value (initially 8).  
Remember —prefix the address with "%" for octal!

DUMP Constants | Symbols | Nodes | Tree  
Dumps the desired item.

Exits the debugger, just like the "/" command.

FLags [#1 [ [,] #2] ]  
If #1 is present, sets DB+0 to that value. If #2 is present, sets DB+1 to that value. The two debugging flags are stored at DB+0 and DB+1. A higher-level method of setting/resetting debugging bits is the SET/RESET command.

FORMfeed | FF  
Sends a form feed to the output device.

Forward [#nodes]  
Moves the "current node" forward #nodes nodes. (Default is 1 node)

Gets this information.

MAP [lexlevel#] [ Sorted | Unsorted]  
Prints a symbol table map of the specified lex level (defaults to current lex level). If Sorted is specified, the map is sorted. Default is unsorted.

MODIFY dbaddr value  
Sets DB(dbaddr) := value. If the current node is the area modified, this command automatically sets the dirty bit for that node.

Next [#]  
Like DAD, but gets node'next.

NODEbuf [node#] [base]  
Dumps in the desired base the contents of the specified node. This is a "raw" dump.  
Note —Since a get'node is done, you could actually enter Debug/iX and modify the node buffer if you wanted to...but if you do that, be sure to mark it "dirty" with NODEDIRTY.

Marks the "current node" as dirty.

NODES [startnode] [endnode]  
Dumps the nodes array. Width defaults to 80 for interactive, 132 for batch.

NOSUPPress [warning# | SUPPress | NOSUPPress ] [...]  

OUTFile [text]  
Uses "text" as a file name and tries to FOPEN it. If successful, then all subsequent "send" output generated while within the debugger will be sent to the specified file. The file can be closed either by exiting the debugger or by entering "OUTFILE" with no parameters. (The default device is LP.)

PARMs [base]  
Prints a stack trace and, for every marker, shows the last 8 values prior to Q-3. Because this information takes room on the output line, only the name of the routine is shown. See also the STACK command. Base is one of: Hex, Integer, Octal. Default = Octal

PP [node#]  
Calls pretty-print starting at the specified (or current) node number.

Sets the execution priority for the SPLash! compiler.

PROCedure procname  
This command returns the address for the named procedure. This command is only available under MPE V.

Invokes the PSCREEN module which reads the terminal memory and dumps it to the line printer.

RESET [debugoption [debugoption ...]]  
Resets the specified debug options to true. These are the same options settable via ASK. RESET with no parameters will report the currently SET debug bits. RESET ALL resets trace'flag and trace'flag2 to 0.

Exit the debugger, just like the slash (/) command.

Root [#levels]  
Prints the nodes tree starting at the root, for the specified number of levels (defaults to 1). Changes the "current node" to root.

SAVenode [#levels]  
Prints the nodes tree for 1 level, starting at the node last referenced before entering the debugger. SAVE makes "current node" be this value too.

Note —At entry to the debugger, "current node" has this value.

SEQ #  
Finds the first node with a sequence number (left 5 digits) >= the number you specified.

SET [debugoption [debugoption ...]]  
Sets the specified debug options to true. These are the same options settable via ASK. SET with no parameters will report the currently set bits. SET ALL sets trace'flag and trace'flag2 to $FFFF, which is probably not desirable.

SOn [#]  
Like DAD, but gets the first son.

STack [base]  
Prints a stack trace, so you can see who called what. (see also the PARMS command) Base is one of: Hex, Integer, Octal. Default = Octal

Displays the same statistics that $CONTROL STATISTICS shows.

SUPPress [warning # | SUPPress | NOSUPPress ] [...]  
Suppresses/unsuppresses the printing of specified warnings. For example, the command "NOSUPPRESS 5" allows warning #5 to be generated, which is "LOGICAL SHIFT LEFT EMITTED". After [un]suppressing specified warnings, the status of the warning suppression bit-map is reported.

SYMbol # [style]  
Displays the symbol for the specified symbol id. Style, which defaults, to 0, is used to specify the style in which the symbol is to be displayed:

SYMBUF symbol# [base]  
Dumps the symbol table node for the specified symbol id. This dump is in a raw format.

TAil [#]  
Like DAD, but gets node'tail.

Calls terminate.

TRee [#1 [ [,] #levels]  
Prints the nodes tree for #levels (defaults to 1) Sets the "current node" to #1 (if specified, otherwise the old "current node" is used as #1).

"Walks" all the nodes of the tree and then reports on it's findings.

Sets the "want'debugger" flag at exit of debugger. This will cause the next get'node to enter the debugger.

#1 [#levels]  
Identical to TREE #1 [#levels] Example: 48 2 dumps 2 levels starting at node 48

Calls the COMMAND intrinsic with the rest of the input.

/ (forward slash)  
Exits this debugger.

(top) (index)

Appendix E : SPLash! & Debug/iX Macros


This appendix explains the SPLash! macros used for debugging with the native mode debugger, Debug/iX. Use these two facilities together to troubleshoot or analyze your programs.

SPLash! Macros for DEBUG

The following steps will guide you in using SPLash! macros with Debug/iX to locate variables.

Step 1 The first step in using SPLash! macros with the debugger, is to compile and link your program with SPLash! using the $MAP control option. Use the SPLash! output listing as your variable reference.

This will generate a variable map so you can locate variables within your program. Outer block variables will be located at positive offsets from DB. Procedure parameters will be as located at negative offsets from Q; procedure variables will be located at positive offsets from Q.  

Step 2 Start your program and load the SPLash! macro file. Use the following commands.

    : run progname;debug <<<<<<< start debug nmdebug> use splash.macro <<<<<<< load splash macros

Running your program with ";debug" invokes the debugger after loading your program. Next, at the debug prompt "nmdebug>", enter "use splash.macro" to load the SPLash! macro file into the debugger.  

Step 3 Locate the section of code that is of interest to you. Place a breakpoint there. Execute to that breakpoint. The following commands may be used to perform Step 3.

    nmdebug> dc program len <<<<<<< dc = dump code <<<<<<< program = program label <<<<<<< len = amount of code to dump nmdebug> b offset <<<<<<< set a breakpoint nmdebug> c <<<<<<< execute to the breakpoint


Step 4 Examine variables. There are several ways to do this. Two examples of examining variables using 2 of the SPLash! macros are presented here. These macros are:

Using your SPLash! map listing, locate a DB relative variable you want to examine. Then issue this command:

    nmdebug> dcmdb (offset,len)

Where offset is the number from the SPLash! variable map, and len is a halfword value.

Now let's look at a Q relative variable. Using your SPLash! map listing locate a Q relative variable you want to examine. Then issue the command:

Again, offset is the number from the SPLash! variable map, and len is a halfword value. Note that Q relative variables come and go with the execution of your program, so the procedure of interest must be active when viewing Q relative variables.


Macro Name     Use

             dcmdb Display DB relative memory   dcmq Display Q relative memory   dcms Display S relative memory   j Jump PC+8, skips next two instructions   odd Return TRUE if byte address   cmdb Returns DB relative memory address   cmq Returns Q relative memory address   cms Returns S relative memory address   compare Compare memory   dcm Display 32 bit memory   dcm1 Display 16 bit memory   get16 Return 16 bit memory value   leftright Tell user which part of address is significant   armall Enable all breakpoints   disarmall Disable all breakpoints   untrap Disable a breakpoint

Macro Definitions

The armall, disarmall, and untrap macros are useful when a SPLash! program is compiled with one (or more) of the $BREAK= options.

If a SPLash! program was compiled with $BREAK=ALL, then conditional breakpoints are emitted at the entry and exit of every procedure and subroutine, at every label (e.g., LOOP:), and at the entry/exit of the program.

When the program is run, these conditional breakpoints cause the code to be interrupted, and the debugger is invoked (quietly). The debugger determines which type of conditional breakpoint was encountered. It then checks if the user wanted that breakpoint to interrupt the program (i.e., is that type of trap ARMed?), and (if armed) falls into the debug code.

    mac armall {trap trace arm; trap} mac disarmall {trap trace disarm; trap} mac untrap (trapname) {trap !trapname disarm; trap !trapname}

    /* Usage: =cmdb (3) returns value at DB+3 /* =cmq (-4) returns value at Q-4 /* =cms (-2) returns value at S-2

    mac cmdb (offset) {return get16 (r4 + 2 * offset) } mac cmq (offset) {return get16 (r5 + 2 * offset) } mac cms (offset) {return get16 (r6 + 2 * offset) }

    /* Usage: j Sets a temporary breakpoint 2 instructions forward. /* Useful for jumping around a BL instruction.

    mac j {env error 0; ignore quiet; b pc + $8, -1; if error = -#30 then { env error 0; ignore quiet; b pc + #12, -1; }; if error <> 0 then wl "Unable to set breakpoint" else c; } /* err -#30 is: breakpoint already in code at that spot

    /* Usage: compare (r4+10, r5+10, 10)

    mac compare (x1 : ptr, x2 : ptr, len : int) { while len > 0 do { if [x1] <> [x2] then & wl "Mismatch at WORD ",x1," = ",[x1], " vs ", x2," = ",[x2]; loc x1 = x1 + 4; loc x2 = x2 + 4; loc len = len - 4; }; }

    /* Usage: procname (pin)

    mac procname (i) {dv pibx (i) + $119c, $30/4, s}

    /* Usage: getproc (pc) --> returns procedure name (without "+...")

    var my_proc_name = " "

    mac getproc (addr : lptr) { var my_proc_name = nmproc (addr); var my_proc_name = str (my_proc_name, 1, strpos (my_proc_name + "+", "+") - 1) }

    /* Usage: ifstmt (pc) --> true if we are at a "Stmt" opcode

    mac ifstmt (addr : lptr) { if ([addr] band $ffff0000) = $20000000 then return true else return false}

    /* Usage: exstmt (pc) --> extracts the statement # of a "Stmt" opcode

    mac exstmt (addr : lptr = 0.0) { if lptr (addr) = 0.0 then loc addr = pc; return [addr] band $7fff}

    /* Usage: liststmts (pc) --> lists "Stmt" opcodes starting at addr /* stops when it hits end of routine.

    mac liststmts (addr : lptr = 0.0) { if lptr (addr) = 0.0 then loc addr = pc; getproc (addr); loc saveproc = my_proc_name; loc mypc = addr; wl my_proc_name; while my_proc_name = saveproc do { if ifstmt (mypc) then wl mypc," Stmt ", exstmt (mypc):"#"; loc mypc = mypc + 4; getproc (mypc); } }

    /* Returns "true" of instr at pc is a conditional breakpoint

    mac istrace (addr = 0.0) { if lptr (addr) = 0.0 then loc addr = pc; loc instr = [addr]; if (instr = $1600e) or (instr = $1400e) or & (instr = $1e00e) then return true else return false}

    mac finddl { var dlregister nmaddr ("_dl_register","data") - nmaddr("$global$","data") + r27; var dlsize [dlregister] }

    mac arg (n) {dv r6-(4*(!n))}

    mac listargs (argbase, maxn = 64) { var i = 3; var itemnum = 1; var itemval = 0; while (i < !maxn) and (itemnum <> 0) do { var itemnum = [!argbase - (4*i)]; var itemval = [!argbase - (4*(i+1))]; wl "Arg # ", i/2:"#", " = # ", itemnum:"#", ", value = ", itemval, " --> ", [itemval]; var i = i+2; } }

    mac init { var p_c pc ; var curseq 0 }

    if mode = 'nm' then init;

    mac next { var p_c p_c + 4; while [!p_c]>>$10 <> $2000 do var p_c p_c + 4; var curseq [!p_c] band $1fffff; wl !p_c; pj !p_c }

    mac prior { var p_c p_c - 4; while ([!p_c]>>$10 <> $2000) and (p_c > 0) do var p_c p_c - 4 ; var curseq [!p_c] band $1fffff; wl !p_c; pj !p_c }

    mac find (newseq) { if newseq > curseq then & while curseq < newseq do {next;wl "Seq # ",asc(curseq,"#")}& else & while curseq > newseq do {prior;wl "Seq # ", asc(curseq,"#")}}

(top) (index)

Using DEBUG on MPE/iX

This is a brief summary of the more basic commands available in Debug/iX. Debug/iX can be used to debug native mode (NM) code or compatibility mode (CM) code.

Debug/iX has an extensive amount of help information available. The HELP command describes the basic help facility. Using the HELP command, along with the CMDLIST, FUNCLIST, and ENVLIST commands, will generate information on almost any feature you are looking for.

The topics discussed in this section cover things like; using the LIST command to generate information, which commands can be used for displaying data, and how you can use the Singlestep and Breakpoint instructions for controlling the execution of your program. Lastly, an abbreviated list of commonly used Debug/iX commands is presented.

The LIST Command

The LIST Command, and it's variations, can be used to generate command names for functions that you may wish to use.

Frequently, commands ending with the letters "LIST" follow a similar pattern: the "IST" can be abbreviated (i.e., CMDL is equivalent to CMDLIST), and the first parameter is a wildcard, via the LISTF command (CMDLIST @Z@).

CMDLIST cmdpattern [category] [what]

FUNCLIST funcpattern [catogory] [what]

ENVLIST envpattern [category]

For a complete list of commands that "list" things, try: CMDLIST @LIST or ALIASLIST @LIST .

The ALIASLIST command is used because Debug/iX supports a synonym feature that it refers to as an "alias". The CMDLIST command is actually an alias for the CMDL command. Indeed, most of the apparent commands ending in "LIST" are simply predefined aliases for commands ending in "L".

(top) (index)

Displaying Data

The DISPLAY commands display information on your screen in a variety of formats.

DV address [#words] [base] [recw] [recb]

DDB dbaddr [#halfs] [base]

qaddr [#halfs] [base]
saddr {#halfs] [base]

DR dr [register]

(top) (index)

Singlestep & Breakpoint

These instructions are useful for controlling the execution of your program.

Ss [#instructions]

B address [count] [<LOUD] | QUIET>] [cmd]

BD [@]

(top) (index)

Miscellaneous Debug/iX Commands

C (and Exit)



SET CROFF WHELP WON WOFF RED VW virtaddr [name] VK [virtualwindow#]

(top) (index)

Appendix F : Sample Code

SPLash! Sample Code

The code samples presented in this section include Dynamic Procedures, the MYCOMMAND intrinsic, and the LOADPROC intrinsic. These code samples were selected as models because they reflect the kind of information that SPLash! users commonly request when coding for the native mode platform.

Dynamic Procedures

! dynamic.inc   88/03/02  cap = ia, pm, ba
! Purpose:
!    Exercise dynamic procedure calling.
! PM:
!    Since 1.1 of MPE XL, privmode is needed to usefully call
!    printfileinfo on files 1..8
! Method:
!    HPGETPROCPLABEL is used to get an NM plabel for PRINTFILEINFO.
!    PRINTFILEINFO is then called for file numbers [0]..8
!    (PARM is used for the lower limit.).
!    PRINTFILEINFO is called in 4 different ways, dictated by
!    file# mod 4:
!         0:  pcal 0:     tos := plabel;  assemble (pcal 0, native)
!         1:  dynamic pcal:         pfi(fid);
!         2:  pcal of dynamic proc: assemble (pcal pfi)
!         3:  dynamic pcal, stacked parm:  pfi(*)
!    NOTE: not all of the 8 files are open!!!!!
! Success:
!    9 file "tombstones", some of which are for non-open files.
! Failure:
!    program abort, or no file "tombstones".
$control stmt


double d := 0d, dummy, plabel := 0d, status := 0d;

integer array buf (0 : 40);

integer fid, len, new'sreg, old'sreg, parm = q - 4;

byte array buf' (*) = buf, procname (0 : 40);

intrinsic ascii, getprivmode, getusermode, hpgetprocplabel, print, quit;


procedure pfi (fid); value fid; integer fid; option dynamic, native, nocc;

! Note: the above allocates 32 bits of storage, for a variable ! called "pfi". Once "pfi" has been assigned a value (a plabel), ! it can be called just like any other procedure. ! ! NOTE: do NOT use LOADPROC to get a value for "pfi" ... LOADPROC ! quite nicely loads a CM-plabel (16 bits), which is very useful ! when you are writing SWITCH code, but not at all useful for ! calling from ANY native mode program!


! Note: the "intrinsic hpgetprocplabel;" results in: ! ! procedure hpgetprocplabel (procname, plabel, status, first'file', ! case'sensitive); ! value case'sensitive; ! double dummy1, dummy2, status, plabel; ! byte array procname, first'file'; ! logical case'sensitive; ! option external, native, extensible, uppercase, nocc, ! variable, intrinsic; <<*************************************************************>>

move procname := "-PRINTFILEINFO-"; hpgetprocplabel (procname, plabel, status); if status <> 0d then ! 0d = ok quit (1); ! or, use new catalog stuff ! to display error.

! NOTE: the second parameter to hpgetprocplabel, plabel, ! is a scratch 32-bit integer and NOT the name of the ! option-dynamic routine! If you tried to use the name of ! that routine (pfi) as the actual parameter, then SPLash! would ! interpret it as an attempt to call pfi. ! ! OK, we now have the 32-bit plabel for the routine, let's ! associate it with our "dynamic" procedure...

@pfi := plabel;

getprivmode; ! so we can call printfileinf (1..8)

! Now, let's call it in four different ways:

for fid := parm until 8 do begin

push (s); old'sreg := tos; ! remember where S was, to check for ! stack problems (Stan's debugging)

print (buf, 0, 0); ! blank line len := move buf' := "FILE # "; len := len + ascii (fid, 10, buf'(len)); len := len + move buf'(len) := "..."; print (buf, -len, 0);

! demonstrate 4 methods of calling dynamically loaded ! procedures...

case fid mod 4 of begin

begin ! an "assemble pcal" of a native-mode procedure works ! ONLY if the programmer manually loads the parameters ! into the correct registers/nm-stack cells ... very ! difficult! print (buf, -move buf' := "Do: assemble(pcal 0,native)", 0); tos := double (fid); ! put first parameter onto stack set (26); ! and move it into R26 tos := @pfi; assemble (pcal 0, native); end;

begin ! The high-level, recommended way of calling dynamic ! procedures...the compiler maps the parameters correctly. print (buf, -move buf' := "Do: dynamic pcal", 0); pfi (fid); end;

begin ! This way usually works, if you have pushed the right ! parameters onto the SPLash! stack, but isn't recommended. ! If an address was by reference, we have to assume that you ! pushed a 32-bit address (or 64-bit address!) onto the stack! print (buf, -move buf' := "Do: assemble(pcal pfi)", 0); tos := fid; assemble (pcal pfi); end;

begin ! This way works too, with same caveats as "assemble pcal pfi" ! I.e.: not recommended. print (buf, -move buf' := "Do: pfi (*)", 0); tos := fid; pfi (*); end;


! Note: both the "assemble (pcal pfi)" and the "pfi (*)" can be ! fooled by a programmer playing around with 32-bit versus 16-bit ! stacked reference parameters. The safest way (and the easiest ! to read & maintain) is to use dynamic procedures with their actual ! parameters (not stacked parameters).

print (buf, -move buf' := "Back from pcal", 0); print (buf, 0, 0);

! check to see if any bugs in compiler left stuff on stack...

push (s); new'sreg := tos;

if old'sreg <> new'sreg then begin print (buf, -move buf' := "***STACK PROBLEMS***", 0); quit (new'sreg - old'sreg); end; end; end.


! mycomman.inc  90/02/20

! Status: apparently working

integer procedure mycommand (comimage, delimiters, maxparms, numparms, parms'd, dict, defn); value maxparms; integer maxparms, numparms; byte array comimage, delimiters, dict; double array parms'd; byte pointer defn; option variable, splash;


double lims;

integer array buf (0 : 40);

logical parmcount = q-4, lastflag := false, lmaxparms = maxparms, start, endx, crblank := %6440, status = q-1;

integer length = endx, lims'lower = lims, lims'upper = lims + 1, new's, ! value of S at exit save's, ! value of S at entry s0 = s - 0, xreg = x;

byte array buf' (*) = buf, default'delims (0 : 3);

byte pointer command = start, pntr = comimage;

define cc = status.(6:2) #, cce = 2 #, ccg = 0 #, ccl = 1 #;

label exit'cce, exit'ccg, exit'ccl;

intrinsic ascii, debug, print, quit;

<<--------------------->> subroutine fail (n); value n; integer n; begin

print (buf, - move buf' := "Fail # ", %320); print (buf, - ascii (n, 10, buf'), 0);


end <<fail sub>>; <<--------------------->>

push (s); save's := tos;

move default'delims := (",=;", %15);

tos := 0; push (q); lims := tos;

if not (0 <= maxparms <= %20000) then fail (1); ! maxparms not in range

xreg := @parms'd + (maxparms & asl(1)) - 1;

if parmcount.(14:1) then begin <<extract command>> tos := @pntr; assemble (dup, dup); @command := tos; move * := * while ans, 0; @pntr := tos; length := tos - @command; if parmcount then tos := search (command, length, dict, defn) else tos := search (command, length, dict); if (mycommand := tos) = 0 then go exit'ccl; end else mycommand := 0;

if not (parmcount.(10:1)) then @delimiters := @default'delims;

<<format parameters...>>

xreg := 0;


scan pntr while crblank, 1; assemble (dup, dup); @pntr := tos; start := tos; tos := 0; go scanalphnum;


scan pntr while crblank, 1; @pntr := tos; if < then go checkfunny;


tos := tos lor %40;


tos := pntr; assemble (del);

if = then begin <<alphabetic>> alph: tos := tos lor %200; tos := @pntr; assemble (dup); move * := * while as, 1; @pntr := tos; end;

if > then ! SPLash! problem here at ">" begin <<numeric>> tos := tos lor %100; tos := @pntr; assemble (dup); move * := * while n, 1; @pntr := tos; end;

if = then go alph;

endx := @pntr;

! possibilities now: ! 1. a delimeter, ! 2. a blanks-field within parameter, ! 3. a blanks-field just before delimeter, or ! 4. a special character that's part of parameter.


scan delimiters until (%6400 lor logical(pntr)), 1;

if carry then begin ! 1. character is cr, ! 2. character is special or blank.

tos := pntr;

if s0 <> %15 then begin assemble (delb); @pntr := @pntr + 1; if tos = " " then go doblank; go dospecial; end;

lastflag := tos; tos := xreg; tos := lims; tos := @pntr & lsr (1); assemble (ddup, cmp); if < then tos.(00:01) := 1; xreg := tos; if not (tos <= xreg <= tos) then !rrorexit (mycommandhang, 6, 1); fail (2); xreg := tos; end;

<< a delimiter found >>

tos := tos - @delimiters; ! delimiter position in <delimiters>.

if logical (s0) > 31 then !rrorexit (mycommandhang, 6, 2); fail (3);

tos := endx - start; ! parameter length

<<special case: no parameters in image>>

if = and lastflag and xreg = 0 then go exit'cce;

if logical (s0) > 255 then !rrorexit (mycommandhang, 20, 1); fail (4);

tos := tos lor (tos lor (tos & lsl(8)));

if xreg >= maxparms then begin ddel; go exit'ccg; end;

parms'd (xreg) := tos; xreg := xreg + 1; @pntr := @pntr + 1;

if not (lastflag) then go nextparm;


cc := cce;

if false then exit'ccl: cc := ccl;

if false then exit'ccg: cc := ccg;

if parmcount.(12:01) then numparms := xreg;

push (s); new's := tos;

if new's <> save's and numparms > 0 then begin print (buf, - move buf' := "Stack-error: old S = ", %320); ascii (save's, 8, buf'); print (buf, -6, %320); print (buf, - move buf' := ", new S = ", %320); ascii (new's, 8, buf'); print (buf, -6, 0); fail (-1); end;

end <<mycommand proc>>;

LOADPROC Intrinsic

! loadproc.inc  88/12/07

integer procedure loadproc'nm (procname, library, plabel); value library; integer library; double plabel; byte array procname; ! terminated by a special char

! note: mapping of library (0,1,2,3,4) to xl: ! 0 nl.pub.sys ! 1,2,3,4 first xl loaded with ! ! return value: 0 = ok, non-0 = failure ! note that this differs from mpe v's loadproc result!


equate max'len = 63;

double original'case := 0d, status := 0d;

integer len := 0, status'1 = status, status'2 = status + 1;

logical my'status'reg = q-1;

byte array buf' (0 : max'len + 2), firstfile' (0 : 29);

byte term'char;

virtual byte pointer ptr'firstfile', ptr'procname';

define my'cc = my'status'reg.(06:02) #;

label end'proc;

Procedure hpgetprocplabel (a, b, c, d, e); byte array a, d; double b, c, e; option native, variable, external, uppercase, intrinsic, extensible, nocc;

Procedure hpfirstlibrary (a, b, c); byte array a; double b, c; option native, variable, external, uppercase, extensible, intrinsic, nocc; <<------------------------->> subroutine fail (n); value n; integer n; begin

loadproc'nm := n; ! error result

go end'proc;

end <<fail sub>>; <<------------------------>>

loadproc'nm := 999; ! unknown error plabel := 0d; my'cc := 1; ! ccl

! handle old and new style procedure names...

if procname = alpha or procname = "_" then begin ! old style, 1 terminator at end. ! we need to determine length of proc name, and then ! copy into a local buffer... len := 0; while (len <= max'len) and ((procname (len) <> special) lor (procname (len) = "_") ) do len := len + 1; if len > max'len then fail (-502); ! "entry name too long" move buf'(1) := procname, (len); buf' := " "; ! leading terminator buf'(len + 1) := " "; ! trailing terminator ! remember where local buffer is... @ptr'procname' := virtual (@buf'); end

else ! new style (term at start & end) begin ! use caller's buffer... @ptr'procname' := virtual (@procname); end;

! determine if we need to lookup a library name...

if library = 0 then @ptr'firstfile' := 0d else begin hpfirstlibrary (firstfile', status); if status <> 0d then fail (-123); ! "invalid HPFIRSTLIBRARY" @ptr'firstfile' := virtual(@firstfile'); end;

original'case := 0d;

hpgetprocplabel (ptr'procname', plabel, status, ptr'firstfile', original'case);

if status <> 0d then loadproc'nm := \status'1\ ! return top word else begin my'cc := 2; ! cce .. ok! loadproc'nm := 0; ! no error end;


end <<loadproc'nm proc>>;

(top) (index)

Appendix G : Technical Background

Technical Background

This section briefly reviews the HP Precision Architecture hardware and MPE/iX operating system.

HP Precision Architecture

HP Precision Architecture is a set of design principles, based on reduced instruction set computing (RISC), that characterizes the newest HP3000 computers.

The main design concepts of HP Precision Architecture are:

Comparing MPE V and MPE/iX

The HP3000 operating system is called the Multi-Programming Executive (MPE). The last release of the original operating system is known as MPE V; the new version that runs on the new HP Precision Architecture machines is MPE/iX. Consequently, the early HP3000s are known as MPE V-based HP3000s and the new machines as MPE/iX-based HP3000s.

This section describes the changing architecture of the HP3000s and their operating systems.

MPE V-Based HP3000s

CISC. The MPE V-based HP3000 is a classic CISC (Complex Instruction Set Computing) machine. Its machine instruction set is large and depends heavily on microcode. The instruction set provides full functionality and many addressing modes. Over the years, the instruction set has grown to accommodate specific language and operating system performance requirements.

Overall Hardware Structure. The MPE V-based HP3000s use a simple stack model to access both code and data. A stack model can be illustrated by a stack of building blocks. Just as building blocks can be placed one on top of another, the stack model in a computer system allows data to be placed on top of the stack, and to be removed from the top.

This constitutes a data access queuing method called last-in-first-out (LIFO). Many sophisticated computer algorithms depend upon the simplicity of the stack and this LIFO queuing capability. When data is placed on the stack, it is said to be "pushed" or "loaded." Removal from the stack is done by "popping" or "storing" the data.

The stack model is used to the fullest and its implementation depends heavily on microcode.

Code and Data Management. Using its stack architecture, the MPE V-based HP3000 divides and explicitly separates code and data into segments. Executable machine code resides in code segments and modifiable data areas reside in data segments. These entities are known to both the microcode and software. Code is not modifiable by normal (non-privileged) means, and this protection is strictly enforced by the microcode. Data segments are modifiable and the memory manager (in software) ensures that the copy in memory is swapped to disc when appropriate.

All stacks are contained within data segments. A stack data segment contains the main data areas built by the compiler when the program is compiled and prepared. Code and data segments are tracked by the Code Segment Table (CST) and Data Segment Table (DST), respectively. These tables are known and modified by both the operating system software and the microcode.

Registers. Registers are high speed data storage areas in CPU. The MPE V-based HP3000 has a variety of registers that perform different functions. Since a register's most important task is to assist in manipulating memory addresses, an individual register's value is often interpreted as a memory address.

Each register is 16 bits wide; consequently the largest value that it can hold is 65535. Since each memory address refers to a 16-bit (two byte) word, the original HP3000s were constrained to a maximum of 128K bytes of addressable memory. Even in 1972, this maximum memory size was a severe limitation. To get around the problem, two 16-bit registers were used for addressing memory, which was then divided into two banks of 128K bytes.

The MPE V-based HP3000 registers are special purpose registers. That is, each register has a unique interpretation in the context of the machine's data and memory management strategy. Since data and memory management are accomplished using the stack, each register contains data used by the operating system to manage the stack.

The most important registers and their relation to the stack are shown in Figure 2.2. They are described below.

The use of these registers imply further limitations in the MPE V-based HP3000s. For example, the stack size is limited because the DL area is addressed negatively, relative to the contents of the DB register. (The instruction set does not make use of DL-relative addressing.) This negative addressing dictates the use of a sign bit, lowering the number of available stack address bits to 15.

Add to this that the machine must be able to address on byte boundaries, and a situation is created that limits the address space to 64K bytes (32K words). All of these registers (except those containing bank numbers) store values relative to the beginning of a memory bank. The full location of the beginning of a code segment is indicated by the PB Bank register and the PB register. Notice, however, that there is no PL Bank register. The implication of this is that no segment can span a bank boundary.

(top) (index)

MPE/iX-Based HP3000s

RISC. As described earlier, the MPE/iX-based HP3000 is designed using HP Precision Architecture, which embraces the concept of RISC (Reduced Instruction Set Computing). As a result, the new generation of HP3000s contains no microcode. Instead, software is used to provide full functionality that can be tailored to the diverse needs of particular languages and application environments.

Overall Hardware Architecture. Like the MPE V-based HP3000, the MPE/iX-based machine also uses the concept of a stack. However, the stack is used differently in the two architectures. Whereas the MPE V-based machines use the stack to accomplish all data and code manipulations, the MPE/iX-based HP3000s use the stack primarily to manage parameters and to track the status of executing procedures. The MPE/iX-based HP3000 does not use the stack to perform calculations; they are performed directly in the registers.

Code and Data Management. The new architecture retains the clear separation of code from data. However, instead of enforcing this separation through hardware, the separation is maintained through system software standards. These standards are actually stringently enforced conventions implemented by compilers (including SPLash!).

Registers. The use of registers in the new machines illustrates the power and flexibility that results from the use of software conventions. The MPE/iX-based HP3000s use general purpose registers, in contrast to the special purpose registers used to manage the stack in the MPE V-based HP3000s. There are 32 general purpose registers (GR0 through GR31) in the new machine; each register can hold 32 bits of data. Only three of these registers have been given specific uses by the hardware architects:

Apart from the above three exceptions, the remaining general registers are treated identically by the hardware and are accessible to the software via the machine instruction set. By convention, certain of these registers are interpreted in specific ways. For example:

In addition to its general purpose registers which are heavily used by the software, the MPE/iX-based HP3000 contains certain other registers that are hardware-managed and that contain primarily status and control information. For the most part, these registers are inaccessible to non-privileged software. For example:

Addressing. The MPE/iX-based HP3000's 32 bit registers, combined with a new scheme for partitioning memory and constructing addresses, enables it to overcome the addressing limitations of the 16 bit MPE V-based machines.

The new architecture provides real and virtual addressing. Real addressing is used in a few rare instances to directly address real semiconductor memory on the machine. Each real address is 32 bits, and thus the MPE/iX-based HP3000 can theoretically support up to 2**32, or four gigabytes, of real memory. (The real memory supported is actually less, because I/O is mapped into part of this address space.)

Virtual addressing is more commonly used. It uses 64 bits: the first 32 bits identify an address space, the remaining 32 bits identify a specific offset within the address space. Each address space is further partitioned into pages of 2048 bytes each; a page can contain either code or data. MPE/iX manages virtual memory to ensure that code and data pages are allocated to the machine's real memory as needed during program execution.

A 64 bit virtual memory address is called a long pointer. It provides the ability to address the maximum amount of virtual memory, however, there is some overhead associated with manipulating this full address. To speed up the addressing process in certain instances where full addressability is not important, the MPE/iX-based HP3000 introduces the concept of a short pointer. This 32 bit address, which is more easily manipulated in the machine's 32 bit registers, relies on the first two bits to identify the address space. These first two bits map to one of four space registers, which are then used in conjunction with the original 32 bit address to quickly construct a virtual address.

(top) (index)


Terms & Concepts

An address in HPPA is a 64-bit quantity that specifies a particular byte in memory. The high-order 32 bits are a `space number', and the low-order 32 bits are a byte offset within the space. A 64-bit address is often referred to as a `long address', because HPPA provides a method of using 32-bit `short addresses' as a performance aid. Hardware automatically translates short addresses to long addresses by using their high-order 2 bits to select a 32-bit space register, thus resulting in a long address.

Block Mode
A method of terminal input flow control that allows a user to edit information on a CRT screen locally without interaction with the HP3000. Pressing the `Enter' key causes the terminal to send the screen data to the HP3000. Block mode uses DC1/DC2/DC1 handshaking to control the actual flow of characters.

Logic branches in software are decision points where the program may take alternate paths depending on a given set of circumstances. In HPPA, a branch instruction will be executed in two clock cycles. The instruction that follows the branch instruction in the code stream is executed before the branch takes effect. This concept is called `delayed branching'. By doing a delayed branch, rather than having extra hardware that would pre-fetch the instruction at the branch target address, the cost and complexity of the CPU is kept down.

A byte is 8 bits.

Prior to Reduced Instruction Set Computing, most computer employed a scheme which relied on a large number of instructions, termed Complex Instruction Set Computing (CISC).

Control Register
HPPA relies on 25 control registers to provide interruption control, memory access protection, and processor state control.

Compatibility Mode
Compatibility mode is used to refer to "things" that are MPE V (or Classic HP3000) oriented.

This is the debug tool that comes with MPE/iX. It can be used to debug any HP-supported languages and works in both native and compatibility modes.

Global is typically used to refer to variables declared in the outer block of a SPLash! or Pascal/iX program.

The GLOBAL and EXTERNAL keywords in SPLash! and SPL allow procedures within subprograms to address selected outer-block variables of the main program without having to know at compile time exactly where the globals are stored relative to DB. In SPL, the addressing for EXTERNAL variables is indirect and is resolved at prep time by the SEGMENTER. In SPLash!, addressing is direct and is resolved at link time by the linker (or at load time by the loader).

A halfword is 16 bits.

The linker program takes as input on (or more) object modules and produces a single executable program file. See the LINKEDIT manual for complete details.

Native Mode
Native mode is used to refer to "things" that are MPE/iX (or HPPA) oriented. For example: native mode code, native mode calling sequence.

Modern CISC computers generally do not have every instruction executed by dedicated hardware. Instead, they are typically implemented as computers with a simpler (and faster) instruction set. A program is written for this simple instruction set which emulates the desired CISC instruction set. This program is usually stored in very fast ROMs. The program's code is referred to as microcode. Some computers have writable microcode, which means that their microcode is stored in RAM and a mechanism exists to replace it with a new version. HPPA computers have no microcode. Instead, their instruction set is implemented directly in the hardware. The stack-based HP3000 computers are microcoded. Some (Series 37, 68, 70 and Micro/3000) have writable microcode.

The pre-fetching of instructions to execute by the HPPA hardware before the program gets to the point of executing them is called pipelining. The pipeline in HPPA is shallow, holding only one extra instruction.

The native mode object file used by the Linker and the loader is called a System Object Module (SOM) file. It contains both relocatable and executable object code. It is analogous to MPE V's USL (User Subroutine Library) file.

The stack model is used to access data, with data queued in a `Last-In-First-Out' fashion; that is, data is placed on top of the stack and then removed from the top. The MPE V based HP3000s are almost completely stack oriented, with few instructions that can address data without also referencing the stack. These machines have special purpose hardware to aid in manipulating the stack. The HPPA machines do not have a stack implemented in hardware, but as in all modern computers, a stack exists. In HPPA, the stack is manipulated explicitly with software instructions to `push' and `pop' data from it.

A word is 32 bits.

(top) (index)


$ADDRARITHMETIC Option $ADR Option $ALIGN Option $ALIGNED32 Option
$ASMCOPYRIGHT Option $BASE Option $BASE Options $BIGDIRECt Option
$BIGPROGRAM Option $BREAK Option $CC Option $CCINTRINS Option
$DEFINE Option $DIRECT Option $DL Option $ECHO Option
$EDIT Option $ERRORS Option $EXTERNAL Option $FASTMOVE Option
$FEATURE Option $FOLLOW Option $GENCODE Option $GENSTAT Option
$HARDWARN Option $IF Option $IMPORTDB Option $INCLUDE Option
$INFO Option $INNERLIST Option $INTERNAL Option $LINES Option
$MPE Option $NATIVE Option $NEGX Option $NEVERLIST Option
$NEWDLDB Option $NMPCAL Option $OBISMAIN Option $OBVARS Option
$OLDREALS Option $OPTMOVE Option $OVERFLOW Option $PAGE Option
$PRIVILEGED Option $PSTRINGS Option $PUSH Option $QUICK Option
$SYSINTR Option $TESTSP Option $THIRTY Option $TITLE Option
$TP Option $TRACE Option $TRACEPCAL Option $TRY Option
$VIRTUALGLOBAL Option $WARN Option $X Option $XREF Option
ABSOLUTE (558,  1159) Address Address Assignments AIF Intrinsics (576 ,  607)
ANYVAR Architected Interface argcargv
Array Allocation ASMLK (1282,  1331) ASMOBJ (1283,  1332) ASSEMBLE (565 ,  5885)
Assembler Instructions Assembly
BCCBlock Mode BR Breakpoints
ByteByte Paramters
Calling a Module Calling a Program Calling from NM Languages Calling Sequences
CIOCISC (8107 ,  8458,  8528) Classic Instructions
CM Instructions CM Programs in SPL CMD Code Generation
Command Files (219 ,  1593 ,  1790) Compatibility Mode (604 ,  721 ,  8473)
Compilation (1472 ,  3128) Compiler Dollar Options Compiler Options (2073 ,  4504) CON (1103,  1106)
CON Pseudo-op Condition Codes Constants (2337 ,  2387 ,  4175)
Control-Y (886 ,  4869) Control Register Cross Referencing (4490 ,  4678)
Data Types DB Address (2463 ,  3897) DB RegisterDebug
Debugging (3143 ,  3494 ,  3515 ,  4217 ,  4333 ,  4678 ,  6268 ,  6700 ,  7052)
Definition Storage Discussion 10 (see LLBL Instruction) Discussion 11 (see Flagged Instructions) Discussion 1 (see Read Switch Register)
Discussion 2 (see Memory Instructions) Discussion 3 (see Hardware Dependent Instructions) Discussion 4 (see Obsolete Instructions) Discussion 5 (see XEQ Instructions)
Discussion 6 (see Limited Support for PCAL Instruction) Discussion 7 (see Loading & Branching Instructions) Discussion 8 (see Pushing & Setting Registers) Discussion 9 (see CON Construct)
DISP DL Area DLSIZE.INC.SPLASH Dyadic Expressions
EDITENDP envp Expressions
Flags (546,  1157 ,  4466) Floating Point Arithmetic (3944 ,  4975) FOR Loops
GETOLDDB.MILLI.SPLASH Global Global Options Global Variables (3692 ,  3933 ,  4451)
HalfwordHALT Hardware Dependent Instructions HP-UX
HPPA HPPA Instructions
Index Register INFO Parameters Inline Code Installation
INTERNAL Option Intrinsic Intrinsic Intercept Method INTRINSIC Option
Intrinsics item_array Itemnum_array itemstatus_array
Linker LinkingLLBL LLSH
MABSMDS MDS.INC.SPLASH (766 ,  6113 ,  6136)
Memory Area Memory Instructions MFDSMicrocode
Migration Issues Mixed Language Compilations Mode ControlMOVE
Native Mode NATIVE Option Negative Addresses NM Procedures
NM Registers NOCC Option Non-local Jumps Non-SPLash Languages
Obsolete Instructions OLDREALS Opcode Compilation OPTION DYNAMIC
P Addressing Parameter Passing (2032 ,  2134 ,  4403) Parameter Types
PARC PARC.INC.SPLASH Pascal (1820,  2376 ,  2672,  4069)
PipeliningPLDA Porting to HP-UX (5491 ,  5512) Privileged Mode
PRIVILEGED Option Procedure Calls Procedure Declaration (1970 ,  4184) Procedure Options
Pushing & Setting Registers
Q Address QUICK Option
RADIX Offsets RCLK Read Switch Register Real Numbers
Reference Parameters Register Usage Replacement Routines RIO
RISC RMSK Runtime Errors
SPL SPLASH (1281,  1330) SPLash! UDCs splash'longjmp
splash'setjmp SPLASH Option SPLASH Procedures SPLASHHL.PUB.SPLASH
SSTStack Standalone Programs (1191 ,  1471) Statement Numbers
Status Register Subprogram Compilation SYSESC.INC.SPLASH System Data Structures
TIOTR TracingTrapping
Variable Allocation Variable Declaration (1969 ,  2309 ,  4682) VARIABLE Option
WIO Word
XEQ XEQ Instructions XREF