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 2003-11-19
Table of Contents
- 1. Introduction
- 2. Installation
- 3. Before you start
- 4. Compiling with SPLash!
- 5. Parameters, Procedures & Conventions
- 6. Beyond SPL
- 7. Using XREF
- 8. Migration Issues
- 9. Run Time Error Recovery
- Appendix A : ASSEMBLE
- Appendix B : Intrinsic Changes
- Appendix C : Compiler Messages
- Appendix D : SPLash! Debugger
- Appendix E : SPLash! & Debug/iX Macros
- Appendix F : Sample Code
- Appendix G : Technical Background
- Glossary
- Index
(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.
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.
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.
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:
HP3000 Computer Systems: Systems Programming Language Textbook
(Part No. 30000-90025)
HP3000 Machine Instruction Set
(Part No. 30000-90022)
HP PASCAL/XL Reference Manual
HP PASCAL/XL Programmer's Guide
HP C/XL Reference Manual
HP C/XL Programmer's Guide
HP Precision Architecture: Precision Architecture and Instruction
Reference, Procedure Calling Conventions Reference Manual
(Part No. 09740-64003)
MPE XL Programmer's Series: System Debug Reference Manual
(Part No. 32650-60017)
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.
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.
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.
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:
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.
splxl.pub.splash Compile to ASM
splobjxl.pub.splash Compile to OBJ
spllkxl.pub.splash Compile to NMPRG
splxlgo.pub.splash Compile & Execute
(top) (index)
About This Manual
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
HP3000 Computer Systems: Systems Programming Language Reference
Manual
(Part No. 30000-90024)
(top) (index)
Typeface Conventions
Bold Important terms. CAPS Command, intrinsic , and filenames.
Italic Publication names, Chapter names, or
to provide emphasis. Fixed Font Screen display and computer output.
<angled brackets> User-specified input is
designated by angled brackets. Terminology
(top) (index)
2 Installation
Introduction
(top) (index)
Overwriting the SPLASH account (default)
:file spltape;dev=tape
:restore *spltape;splash.pub.sys
(Reply to the tape request for "SPLTAPE")
:stream splash.pub.sys
(Reply to the tape request for "SPLTAPE")
(top) (index)
Install in Uniquely Named Account
:setvar accountname "SPLASH"
For example, if you want to install SPLash! in the account named
SPLTEST, you would change the setvar line to the following:
:setvar accountname "SPLTEST"
(top) (index)
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:
Stack decrements on MOVE, SCAN, and byte comparisons. Full MPE V-based HP3000 addressing mode emulation.
Maintenance of all data types.
Virtually all ASSEMBLE statements.
Stack emulation, including register caching of the top stack words.
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!.
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.
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:
2. If so, is there a new MPE/iX or HPPA facility that can be
used, instead of employing PM?
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
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
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
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:
Pushing & Setting Registers
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:
MYPIN := ABSOLUTE (3) / %25; << CALCULATE PIN NUMBER >>
/\
PRIVILEGED MODE OPERATION, SEE DISCUSSION 11.
***** WARNING 1: w211 @ 03211100 X.PUB.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!
(top) (index)
The Role of Privileged Mode in SPL Environments
1. Is this functionality still necessary under the MPE/iX software
environment and the Hewlett-Packard Precision Architecture hardware
environment?
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
LDEA LLSH LSEA SDEA SSEA XCHD
DISP IXIT LOCK PAUS PCN PSDB PSEB
RCLK RMSK SCLK SED SMSK UNLK
CIO CMD HALT RIO SIN TIO WIO
BCC BR LDPN LDPP
(and related instructions)
must be changed to:
ASSEMBLE (BR P+20);
.
.
.
I := 4 + J; << P + 20 >>
This code is easily handled by SPLash!, in addition to being far more
readable and maintainable.
ASSEMBLE (BR LAB1);
.
.
.
LAB1: I := 4 + J;
PUSH and SET Statements
PSHR and SETR Machine Instructions
M | I | T | R | O | C | CC | CST # |
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
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
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
.
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! 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.
SPLASHU.PUB.SPLASH
The UDCs in SPLASHU allow SPLash! programs to be compiled,
assembled, and linked as easily as —
A group called O exists, which will be
used to hold
the assembled files created by the assembler.
Linked programs reside in the PUB group.
Linking is
produced by using the LINK command.
The file to be compiled is
always
in the current logon group.
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.
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.
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.
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.
Compiling
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:
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:
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.
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]
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.
CON EDIT TR ENDP PARC XBR
ABSOLUTE LST MABS MDS MFDS
MTDS PLDA PSTA SST
(top) (index)
4 Compiling with SPLash!
Overview
SPLash! User Defined Commands (UDCs)
spllk foo ! compile, assemble, link
Or,
splash foo ! compile
asmlk foo ! assemble & link
These UDCs make four assumptions that you must follow:
A group called ASM exists which will be
used to hold
the assembler output from the SPLash! compiler.
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.
SPLLK Compiles from <source>.<logon> to <source>.ASM and then
links to <source>.PUB.
spllk source, parm=0, list=$null, info=" ", priv=3, cap="ia, ba",
arecs=40000, orecs=2000, opt="~"
SPLASH Compiles from <source>.<logon> to <source>.ASM.
splash source, parm=0, list=$STDLIST, info=" ", arecs=40000
ASMLK
Assembles <source>.ASM to <source>.O, then links to <source>.
PUB.
asmlk source, opt=" ", priv=3, cap="ia,ba", list=$NULL, arecs=2000
ASMOBJ
Assembles <source>.ASM to <source>.O.
asmobj source, opt=" ", list=$NULL, arecs=2000
SPLOBJ
Compiles and Assembles from <source>.<logon> to <source>.O.
spllk source, parm=0, priv=3, cap = "ia, ba"
SPLASH
Compiles from <source>, resulting in SPLASSM.
splash source, parm=0, list=$STDLIST, info=" "
ASMLK
Assembles <source> to $NEWPASS, then links $OLDPASS to $NEWPASS.
asmlk source=SPLASSM, opt=" ", priv=3, cap="ia,ba", list=$NULL
ASMOBJ
Assembles <source> to $NEWPASS, for deferred linking.
asmobj source=SPLASSM, opt=" ", list=$NULL
UDC Parameters
Compiling Standalone SPLash! Programs
splash FOO
file defer;dev=lp,1;cctl
splash BIGFILE, , *DEFER, , 80000
splash source=FOO; list=$NULL
file defer;dev=lp,1;cctl
splash source=BIGFILE; list=*DEFER; arecs=80000
Assembling & Linking
asmlk FOO
asmlk FOO, , 2
asmobj FOO
link from=FOO.O; to=FOO.PUB
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:
spllk FOO
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
SPLXL Compiles SPL source to assembler
output file.
SPLOBJXL Compiles SPL source to native
mode object file.
SPLLKXL Compiles & Links SPL source
to native mode program file.
SPLXLGO Compiles & Links SPL source
to $OLDPASS, and then runs $OLDPASS.
splxl [text][,[asm]][,[list]][,[info]]
[,[parm]][,arecs]
Command File Parameters
text = Source SPL file
asm = Output assembler file, defaults to $oldpass
obj = Output native mode object file, defaults to $oldpass
list = List file, defaults to $stdlist
info = Pass options to SPLash!, default is null
parm = Pass parms to SPLash!, default is 0
arecs = Max size of assembler output file, default = 40000 records
orecs = Max size of native mode object file, default = 2000 records
cap = Capabilities for program file, default=IA,BA
priv = Priv level for program file, default = 3 (user)
$control subprogram begin procedure upshift (text', bytes); value bytes; byte array text'; integer bytes; begin |
Also, we have a program called UPPER.SOURCE which is:
|
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
chgroup MODULE splobj UPSHIFT, , , "CONTROL SPLASH"
This compiles UPSHIFT.MODULE into UPSHIFT.ASM and then assembles it into UPSHIFT.O. See Chapter 5, Parameters, Procedures & Conventions for details on "CONTROL SPLASH".
chgroup SOURCE splobj UPPER
Compiling & Assembling with the SPLash! Command Files
Linking
UPPER.PUB is now compiled, linked, and ready to run.
Running
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
splobjxl upshift.module,upshift.o,,"control splash"
splobjxl upper.source,upper.o
link from=UPPER.O, UPSHIFT.O; to=UPPER.PUB
run upper.pub;info="hi there"
Mixed Language Compilations Using SPLash!
$os 'mpexl'$ $type_coercion 'representation'$ |
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
chgroup MODULE splobj UPSHIFT, , , "CONTROL NATIVE"
Compiles UPSHIFT.MODULE into UPSHIFT.ASM and finally into UPSHIFT.O, marking all unspecified procedures as native mode callable.
chgroup SOURCE pasxl UPPAS, UPPAS.O
Compiling & Assembling with the SPLash! Command Files
splobjxl upshift.module,upshift.o,,"control native"chgroup SOURCE pasxl UPPAS, UPPAS.O
Linking
link from=UPPAS.O, UPSHIFT.O; to=UPPAS.PUB
Running
run UPPAS.PUB;info="hi there"
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:
Compile UPSHIFT.MODULE into UPSHIFT.O, marking all unspecified
procedures as native mode callable.
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:
Calling a Module
chgroup MODULE
splobj UPSHIFT, , , "CONTROL NATIVE"
procedure upshift (text', bytes);
value bytes;
byte array text';
integer bytes;
option external, native, nocc;
(top) (index)
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.
Alignment
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.
32-bit aligned
Address of a 32-bit item is a multiple of 4 bytes (or 32 bits).
16-bit aligned
Address of a 16-bit item is a multiple of 2 bytes (or 16 bits).
8-bit aligned
Address of a 8-bit item is a multiple of 2 bytes (or 8 bits).
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.
Intrinsic
Passing Parameters
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
Controlling the Mode with Compiler Options
$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
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.
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 2:
This combination is not meaningful, as native-mode
procedures cannot call splash-mode procedures.
Note 3:
This is the default for subprograms.
$control native
implies
$control internal=native, external=native
$control splash
implies
$control internal=splash, external=splash
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.
R1 Scratch register. Frequently used to split apart
32-bit words into two 16-bit parts, and to formulate
large constants.
R2 Return Address for procedures.
R3 Occasionally used by SPLash! as a scratch register.
R4 DB emulation (contains 32-bit virtual address).
R5 Q emulation (contains 32-bit virtual address).
R6 S emulation (contains 32-bit virtual address).
R7 X emulation (32-bit signed value).
R8 Condition Code.
A value < 0 means CCL, 0 means CCE, and
> 0 means CCG.
R9 Carry emulation.
Bit 31 is used for "carry", and bit 30 is used for "overflow".
R10 Currently unused.
R11 Pointer to base of "extra" return stack. The 64 bytes
below R11 are used for floating point scratch variables.
The bytes above R11 contain information needed for
returning from procedures and subroutines.
R12 Index pointing to last mini-marker in our extra return stack.
R13..R18 Currently unused.
R19..R26 General registers used to evaluate expressions.
Lower registers are used first.
R27 Native mode Data Pointer (DP). Never altered by SPLash!.
R28 Typically gets result of typed Native-mode procedures.
R29 Like R28, but only used when calling a procedure that
has a functional value of 64 bits.
R30 Native mode stack pointer. In native-mode procedures,
and in splash-mode when TRACEPCAL is set, is bumped up at
the start of a procedure/subroutine and down at end of a
procedure/subroutine.
R31 Holds return address when calling certain
native procedures and millicode.
SR1..SR3 Used in expressions using fullvirtual addresses.
SPLash! tends to use SR1 first, then SR2, then SR3.
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.
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.
A "fullvirtual" variable is one
whose address requires a full 64 bits.
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:
@ptr32 := 0; and @ptr64 := 0;
An example of using FULLVIRTUAL is shown below, comparing it to a
similar Pascal/iX procedure:
Constants
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:
64-bit aligned
Address of a 64-bit item is a multiple of 8 bytes (or 64 bits).
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.
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.
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.
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.
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.
SPLash! supports compiler control options that can be
specified at compilation time to determine how the compiled program
or subprogram will be called.
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:
(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.
compile
unit Int= Ext= external forward actual Note#
------- ---- ---- -------- ------- ------ -----
program (none) (none) native splash splash #1
program splash native native splash splash
program splash (none) native splash splash
program (none) native native splash splash
Note 1:
This is the default for programs.
program native native native native native
program native (none) native native native
program splash splash splash splash splash
program (none) splash splash splash splash
program native splash splash native native #2
subprogram (none) (none) native native native #3
subprogram native native native native native
subprogram native (none) native native native
subprogram (none) native native native native
subprogram splash native native splash splash
subprogram splash (none) native splash splash
subprogram splash splash splash splash splash
subprogram (none) splash splash native native #2
subprogram native splash splash native native #2
(top) (index)
SPLash! HPPA Register Usage
Register usage:
R0 Stores unwanted bits in register 0.
(top) (index)
6 Beyond SPL
Extensions to SPL
(top) (index)
Variable Declaration: VIRTUAL & FULLVIRTUAL
A "virtual" variable
is one whose address is somewhere in the short pointer space, and
therefore requires 32 bits.
Virtual arrays in the outer block may have up
to 32767 bytes of initial values. All bytes past the initialization
part will be zeroed.
Type OPTION NATIVE procedures implicitly change all reference
parameters to type "virtual" if neither "fullvirtual" nor "virtual"
is explicitly specified.
SPLash!
procedure twice (x);
fullvirtual double x;
begin
x := x * 2;
end;
procedure twice (var x : $extnaddr$ integer);
begin
x := x * 2;
end;
|
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.
The following options are all available in the "option" statement
of a procedure declaration.
DYNAMIC
Example:
Procedure hpgetprocplabel (procname, plabel, status,
dummy1, dummy2);
value dummy1, dummy2;
double dummy1, dummy2, status, plabel;
byte array procname;
option external, native, extensible, uppercase;
...
move procname := "-PRINTFILEINFO-";
hpgetprocplabel (procname, plabel, status, 0d, 0d);
if status <> 0d then
quit (1);
@pfi := plabel;
pfi (fid); ! calls the dynamic procedure
EXTENSIBLE
Note 1
—At present, internal native-mode procedures declared
with "option extensible" will correctly address their
parameters. This is an oversight on our part in not providing you
a way to declare and code a native-mode
extensible procedure as well as simply call existing ones.
Note 2
—Currently, "extensible" also implies that parameters
may be omitted. If you want to omit parameters,
specify extensible
and
variable.
EXTERNAL
FORWARD
INTERNAL
INTRINSIC
Goal Options needed
NATIVE
NOCC
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.
PRIVILEGED
QUICK
Note
—At present, Quick only applies to splash-mode
procedures. It will later be expanded to native-mode procedures.
SPLASH
UNCALLABLE
UNCHECKABLE
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.
VARIABLE
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! 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:
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 (&).
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:
Or,
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.
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:
$NOASMCOMMENTS ! No comments in .ASM output file.
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".
$ADDRARITHMETIC={ALLOW,WARN,ERROR}
=ALLOW
=WARN
This warning is useful if @variable is a native address and
"variable" is a non-byte oriented variable (e.g., integer pointer).
Such address arithmetic is best done by using subscripting, which
works in SPL as well as in SPLash!, and does not rely on the
size of an integer being "1" (SPL) or "2" (SPLash!, native
addresses).
=ERROR
Due to the SPLash! scanner structure, two error messages will be
displayed. The first refers to the address arithmetic. The second,
which is somewhat misleading, states
TYPE INCOMPATIBILITY
.
virtual integer pointer vip;
@vip := @vip + 1; ! BAD, no warning/error
$addrarithmetic = warn
@vip := @vip + 1;
CHECK ADDRESS ARITHMETIC: NATIVE ADDRESSES ARE BYTE-ORIENTED
***** WARNING 1: w340 @ 00016000 T.TEST.SPLISH
@vip := @vip + 1;
ADDRESS ARITHMETIC HAS BEEN DISALLOWED BY $ADDRARITHMETIC=ERROR
***** ERROR 1: e226 @ 00025000 T.TEST.SPLISH
$ADR
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.
R#0 $map
R#1 begin
R#2 byte var1;
R#3 long var2;
R#4 byte var3;
R#5 integer var4;
R#6 byte var5;
R#7 double var6;
R#8 end.
Generating: Node # @ Seq # AsmLine#
Outer Block: 32 @ 8 21
Byte
Name Address# Type/Value
--------------- -------- ----------
VAR1 DB+ 0 byte
VAR2 DB+ 2 long <-- not aligned
VAR3 DB+ 10 byte
VAR4 DB+ 12 integer
VAR5 DB+ 14 byte
VAR6 DB+ 16 double <-- not aligned
No errors, no warnings
DB storage = 10 halfwords (20 bytes) <-- SPLash! reports DB used
Unaligned DB = 3 variables <-- SPLash! informs user of
unaligned variables in
DB area.
:splash svar;info="map,mapbyte,align"
R#0 $map,align
R#1 begin
R#2 byte var1;
R#3 long var2;
R#4 byte var3;
R#5 integer var4;
R#6 byte var5;
R#7 double var6;
R#8 end.
Generating: Node # @ Seq # AsmLine#
Outer Block: 32 @ 8 21
Byte
Name Address# Type/Value
--------------- -------- ----------
VAR1 DB+ 0 byte
VAR2 DB+ 8 long <-- 32 bit aligned
VAR3 DB+ 16 byte
VAR4 DB+ 18 integer
VAR5 DB+ 20 byte
VAR6 DB+ 24 double <-- 32 bit aligned
No errors, no warnings
DB storage = 14 halfwords (28 bytes) <-- SPLash! reports DB used
DB ALIGN waste = 4 halfwords (8 bytes) <-- SPLash! shows DB wasted
due to the use of the
$ALIGN compiler option.
Note
—In many cases, using the $ALIGN option has the same
effect on code generation.
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:
Note
—This option is conceptually different
from the $BIGCOMPILE$ control of Pascal/V, which primarily affects
the compiler's ability to ACCEPT large programs.
The types of breakpoints that can be requested are:
ENTER
Procedure entry. A breakpoint instruction is
emitted as the first instruction of every
procedure.
EXIT
Procedure exit. A breakpoint instruction is
emitted as the first instruction of the procedure
exit code of every procedure.
Note
—"return"
statements, "exit" opcodes, and "falling off"
the end of a procedure all go through common
exit code.
FORMAL
Causes SPLash! to emit a "label" breakpoint at the start of
the code emitted for a "go <formallabel>" statement.
A "proc exit" breakpoint is still emitted just before the
BV instruction for a formal goto if BREAK=EXIT is requested.
LABEL
A breakpoint is emitted at every label used by
the programmer. (i.e., labels generated by the
compiler are not included.)
NONE
BREAK=NONE suppresses all breakpoints. NOBREAK=NONE
selects all breakpoints. (NONE is the opposite of
ALL.)
STMT
Statement. A breakpoint instruction is emitted
at the start of every SPLash! statement.
STUB
Stub code. A breakpoint instruction is emitted
at the start of every native-mode stub SPLash!
emits. (Native-mode stubs are used to translate
from stack-based parameters to the native mode
register/stack based parameters.)
SUBR
Subroutine entry/exit. A breakpoint instruction
is emitted at the start and exit of every subroutine.
Note
—the breakpoint emitted at the start is a
"proc enter" breakpoint, and the breakpoint emitted
at the exit is a "proc exit" breakpoint.
DEBUG/iX B.57.06
DEBUG Intrinsic at: 358.00007004 ?$START$
$1 ($3f) nmdebug > trap list <-- Shows TRAP status
XLIBRARY DISABLED
XARITHMETIC DISABLED
XSYSTEM DISABLED
XCODE DISABLED
BRANCH_TAKEN DISABLED
BEGIN_PROCEDURE DISABLED
END_PROCEDURE DISABLED
LABELS DISABLED
STATEMENTS DISABLED
ENTER_PROGRAM DISABLED
EXIT_PROGRAM DISABLED
$2 ($3f) nmdebug > trap trace_all arm <-- ARM all program-related traps
$3 ($3f) nmdebug > trap <-- Same as TRAP LIST
XLIBRARY DISABLED
XARITHMETIC DISABLED
XSYSTEM DISABLED
XCODE DISABLED
BRANCH_TAKEN DISABLED
BEGIN_PROCEDURE ARMED
END_PROCEDURE ARMED
LABELS ARMED
STATEMENTS ARMED
ENTER_PROGRAM ARMED
EXIT_PROGRAM ARMED
$4 ($3f) nmdebug > trap trace_all disarm <-- Disarm program related
traps
$5 ($3f) nmdebug > trap <-- Same as TRAP LIST
XLIBRARY DISABLED
XARITHMETIC DISABLED
XSYSTEM DISABLED
XCODE DISABLED
BRANCH_TAKEN DISABLED
BEGIN_PROCEDURE DISABLED
END_PROCEDURE DISABLED
LABELS DISABLED
STATEMENTS DISABLED
ENTER_PROGRAM DISABLED
EXIT_PROGRAM DISABLED
$6 ($3f) nmdebug > continue
Use "help trap" at the debug prompt for more information on the trap command.
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.
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.
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
$nocc
procedure p5; no
procedure p6; option nocc; no
procedure p7; option intrinsic; no
procedure p8; option nocc, intrinsic; no
$cc
procedure p9; yes
procedure p10;option nocc; no
procedure p11;option intrinsic; yes
procedure p12;option nocc, intrinsic; no
Note
—The twelve examples noted above show that the
"option intrinsic" has no effect on the CC option. It also
demonstrates that NOCC can override $CC, which is the default
setting.
Options & Intrinsics Example
The next example shows that $CC and $NOCC have no effect on intrinsics.
intrinsic binary; yes
intrinsic debug; no (Special case. See Note)
$noccintrin no
intrinsic ctranslate;
$ccintrin, nocc
intrinsic fopen; yes
Note
—Intrinsics that have "special case" code which turns off
condition-code fetching automatically include the following. In
previous versions of SPLash!, only DEBUG contained the special case code.
DEBUG HPCIGETVAR HPDEVCONTROL HPERRREAD
HPCICOMMAND HPCIPUTVAR HPERRDEPTH QUIT
HPCIDELETEVAR HPDEBUG HPERRMSG TERMINATE
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.
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:
POSSIBLE NEGATIVE CONSTANT COERCED TO LOGICAL
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.
For example:
For information about the debugger, run SPLash! interactively
and ask for debugger help as follows:
Note that SPLash! emits much faster code when no DL-DB area is
being used.
Examples:
BATCH True if compiling from a job
INTERACTIVE True if compiling interactively
OLDREALS True if $OLDREALS is in effect
SPLASH True, always
XOLDREALS \ These options exist to maintain backward compatibility
XSPLASH / with previous versions of SPLash!. They are synonyms
for the OLDREALS and SPLASH options.
In addition, $ENDIF and a limited $ELSE are supported. An example
of this would be the following.
SPLash! also generates a warning if a $IF or a $ELSE statement is
found outside of a $IF block. SPLash!, like SPL, does not
support nested $IFs. Therefore, a $ELSE is allowed only if it comes
after a "$IF ...", and no intervening $ELSE or $ENDIFs have occurred.
Likewise, if the compilation ends while a $IF is in effect, SPLash!
generates a warning to that effect.
Note
—"internal" is quoted to differentiate it from the "option
internal" concept.
This option is generally used only with SPLINTR- format files.
The following example illustrates compiling and linking with
$MILLIMOVE, $MILLISCAN, or $FASTMOVE. Note that $FASTMOVE can only be
used for non-overlapping moves.
Otherwise, it is equivalent to:
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.
[NO]OLDREALS can be specified at anytime in the source, but must be
at the beginning of the statement.
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.
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:
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:
Default: NOSAMESIZEWARN
Otherwise, it is equivalent to:
$CONTROL INTERNAL=NATIVE, EXTERNAL=NATIVE
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.
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.
This option will degrade system performance somewhat,
but it yields much better debugging information.
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.
procedurename$2$subroutinename
subroutinename
Breakpoints can be set in subroutines in this case by
doing:
b procedurename$2$subroutinename [...]
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.
Procedure Options
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.
...
double
plabel,
status;
byte array
procname (0 : 64);
...
procedure pfi (fid);
value fid;
integer fid;
option dynamic, native, nocc;
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.)
Pass parameter mask (via SPL)
Variable
Omit parameters. Don't pass mask. See VARIABLE. Variable,
Intrinsic
Omit parameters, and pass # of parameters
Extensible
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.
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).
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.
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".
SPLash! Compiler Dollar Options
$control segment = foo, errors = 9
$set x9 = on
$if x4=on
$ control list
$if
Or,
$segment=foo, errors = 9, x9=on, if x4=on, $list, $if
In a multiple-option statement, dollar signs ($) are treated like
commas (,).
Dollar Options: INFO parameters and SPLASHG
:run splash.pub.splash;info="control dl=0"
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.
:run splash.pub.splash;info="dl=0, list, set x9=on"
Dollar Options: Reference Listing
At the end of this chapter you'll find a table summarizing
the default value and functionality for each dollar control option.
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.
No warnings or errors are generated when SPLash! compiles address
arithmetic statements. This is the default addrarithmetic value.
SPLash! generates a warning (#340) when it compiles expressions
of the form:
@variable + expression
@variable - expression
expression - @variable
expression + @variable
SPLash! generates an error (#226) when it compiles expressions
of the form:
@variable + expression
@variable - expression
expression - @variable
expression + @variable
Example:
$addrarithmetic=allow
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.
R#1 $control native
R#2 $control adr
R#3 begin
R#4 integer i,j,k,l,m,n;
******** I DB+ 0 ($0000, %000000)
******** J DB+ 1 ($0001, %000001)
******** K DB+ 2 ($0002, %000002)
******** L DB+ 3 ($0003, %000003)
******** M DB+ 4 ($0004, %000004)
******** N DB+ 5 ($0005, %000005)
R#5
R#6 intrinsic print;
Parameter @ Location
--------------- ---------
Parm#1 @ R26
Parm#2 @ R24
Parm#3 @ R23
R#7 intrinsic createprocess;
Parameter @ Location
--------------- ---------
Parm#1 @ R26
Parm#2 @ R25
Parm#3 @ R24
Parm#4 @ R23
Parm#5 @ PSP-$0034
R#8
R#9 procedure proc1(ii,jj,kk,ll,mm,nn);
R#10 integer ii,jj,kk,ll,mm,nn;
R#11 begin
Parameter @ Location
--------------- ---------
II @ R26
JJ @ R25
KK @ R24
LL @ R23
MM @ PSP-$0034
NN @ PSP-$0038
R#12 2 integer my'i,my'j,my'k;
******** MY'I Q + 1 ($0001, %000001)
******** MY'J Q + 2 ($0002, %000002)
******** MY'K Q + 3 ($0003, %000003)
R#13 2 end;
R#14
R#15 proc1(i,j,k,l,m,n);
R#16 end.
$ALIGN
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.
:splash svar;info="map,mapbyte"
Now, run SPLash! with the $ALIGN compiler option.
$ALIGNED32
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.
$ALIGNED32ALL
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.
$ALLOCQ
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.
integer year;
procedure dumb;
begin
double time = q + 1;
integer date = q + 3;
tos := clock; ! allocates q+1, q+2
tos := calendar; ! allocates q+3
year := calendar.(00:07);
end;
$ALLOWBYTES
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
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
ASMCOPYRIGHT controls whether or not SPLash! emits $COPYRIGHT and
$VERSION strings into the assembler output.
$BASE = {8, 10, 16}
$BASE = {OCT, DEC, HEX}
Sets the desired output base for use in debugging output.
This option effects listing output when $ADR and $MAP are used.
$BIGDIRECT
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.
$BIGPROGRAM
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.
(top) (index)
$BREAK = {ALL, ENTER, EXIT, FORMAL, LABELs, NONE, STMT, STUBs, SUBRs}
BREAK tells SPLash! to emit breakpoint instructions at specified
places in the code. NOBREAK tells SPLash! not to emit breakpoint
instructions. The values in effect at the end of compilation are the
values used. Breakpoints can be used in conjunction with Debug/XL's
TRAP command. They DO significantly slow a program's execution, so
they should be used only while debugging.
ALL
Sets/resets all of the breakpoint types.
BREAK=ALL sets all breakpoint types. NOBREAK=ALL
resets all breakpoint types.
Once a SPLash! program (or subprogram) is compiled with
breakpoints (and linked), the breakpoints can be used by
doing the following:
run program;debug
$CARRY = {DETECT, IGNORE}
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.
$CC
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.
$CCINTRINS
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.
! returns CC?
procedure p1; yes
procedure p2; option nocc; no
procedure p3; option intrinsic; yes
procedure p4; option nocc, intrinsic; no
$ccintrin ! the default ! returns CC?
$CHECKSTACK
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
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.
$CODE
Accepted, has no affect in SPLash!
$COERCE
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:
byte array ba (0:9);
logical six := 6;
ba := ba (six + -2);
Note that this message might appear twice due to a quirk of
SPLash!'s parsing. However, code will be emitted as before.
$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.
$copyright "Copyright 1987 Allegro Consultants, Inc." &
$ "Allegro 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."
$CSTRINGS
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.
run splash.pub.splash
$debug
help
abort
$DEBUGATEND
If DEBUGATEND is true at the end of compilation, it invokes
the SPLash! debugger after generating code.
$DEFINE
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
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.
$ECHO "text"
The text string will be echoed to $STDLIST via the PRINT
intrinsic.
$EDIT
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 = {SPLASH, NATIVE}
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.
$FASTMOVE
Used with $MILLIMOVE to tell SPLash! that MOVE instructions
that follow will not have overlapping source and target
addresses. See $MILLIMOVE for an example.
$FEATURE = {ALLOCQ, CLEANFOR, OPTMOVE, NEWDLDB}
Broken into separate dollar options. (See ALLOCQ, CLEANFOR, OPTMOVE,
and NEWDLDB.)
$FOLLOW = #
$NOFOLLOW
FOLLOW= causes SPLash! to report compilation progress to
the system console every # lines. As a special case, if #
is 0, then SPLash! reports as it starts compiling every
procedure. Progress is reported via the PRINTOP intrinsic.
$GENCODE
If GENCODE is not selected at the end of compilation, then machine
code will not be emitted.
$GENSTAT
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.
$HARDWARN
If HARDWARN is selected, then all non-suppressed warnings are
treated as errors.
$IF X# = {ON, OFF} THEN
$IF
The IF command is supported as in SPL. Additionally,
compiler options may follow a $IF on the same line, including a
terminating $IF. In SPL anything after the "on" (or "off")
was ignored by SPL. SPLash! doesn't ignore extra text
after the "on" or "off" because it supports limited "OR" and "AND"
capability.
$if x1 = on $list $if
$if x1 = on then
Other options accepted with the IF command include the following.
$if <option> [ <OR | AND> <option> ]
Where option can be one of the following:
X# = ONE
X# = OFF
$IF X1 = ON
...
$ELSE
...
$ENDIF ! or simply, $IF
$IMPORTDB
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
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.
$INNERLIST
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 = {SPLASH, NATIVE}
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.
$LINES = #
$NOLINES
As in SPL, except NOLINES disables pagination completely.
$LIST
As in SPL, except it can be overridden by NEVERLIST.
$LOWERCASEINTRINS
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.
$LOWERCASESEARCH
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.
$MAP
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
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"
$MILLIMOVE
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.
splobjxl testprog info="millimove,milliscan,fastmove"
link from=$oldpass,moveo.milli.splash;to=testprog.pub
$MILLISCAN
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.
$NATIVE
If NATIVE is true, then this is equivalent to:
$CONTROL INTERNAL=NATIVE, EXTERNAL=NATIVE
$CONTROL INTERNAL=SPLASH, EXTERNAL=SPLASH
$NATIVEONLY
This option must occur before the first BEGIN.
$NEGX
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.
$NEVERLIST
If NEVERLIST is true, then listing lines are suppressed
regardless of the setting of LIST.
$NEWDLDB
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.)
$NMPCAL
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.
$OBISMAIN
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.
$OBVARS="obname"
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
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.
$OPTMOVE
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 = {IGNORE, TRAP, DETECT, TEST}
OVERFLOW is maintained in register R9. Bit 30 is used to remember OVERFLOW.
$PAGE ["text"]
As in SPL.
$PASCALIDS
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 (:=).
$PASCALSEARCH
Tells SPLash! to replace the embedded primes (') in intrinsic names
with underscores (_) before searching intrinsic files.
$PHASE
This obscure SPL option is ignored.
$POP
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.
$push, fastmove
move p1 := p2, (n);
$pop
$PP
If PP is true at the end of compilation, then the original
source code (after expanding defines) is "pretty-printed"
to SPLLIST (list file).
$PPC
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.
$PPEXPANDINTRIN
Tells SPLash! to expand intrinsic declarations into equivalent
external procedure declarations. Used with $PPC.
$PPSHORTPTRS
Converts 64 bit pointers to 32 bit pointers.
$PRIVILEGED
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.
$PSTRINGS
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.
"..."#M -> Appends a single carriage return
"..."#O -> Appends a single null
"..."#7 -> Appends a single ASCII bell
For example,
move msg:="hello world"#13#10;
.
$PUSH
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).
$push, fastmove
move p1 := p2, (n);
$pop
$QUICK
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.
$REGVARS
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;
$SAMESIZEWARN
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
SOURCE requests a listing of all source records. NOSOURCE suppresses a
listing of source text.
$SPLASH
If SPLASH is true, then this is equivalent to:
$CONTROL INTERNAL=SPLASH, EXTERNAL=SPLASH
$SPLASHG
Using NOSPLASHG tells SPLash! not to use the
SPLASHG.PUB.SYS
file.
$SPLASHEXT
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.
$SPLASHINTRINS
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).
$STACK = #
(Option may be deleted in future release)
$STATISTICS
If STATISTICS is selected at the end of compilation,
internal compiler statistics will be displayed.
$STMT
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.
$SUBPROGRAM
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.
$SUBRNAMES
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:
$SUPPRESS = #
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
.
$SYMLEN=#
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.
$SYSINTR
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
TESTSP uses register 25 to pass a desired new SP value
to the SPLash_checksp millicode routine.
$THIRTY
This obscure SPL is ignored.
$TP
This obscure SPL is ignored.
$TITLE ["text"]
As in SPL.
$TRACE
This option is ignored.
$TRACEPCAL
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
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.
$TWENTY
This obscure SPL is ignored.
$ULIST
This obscure SPL option is ignored.
$UNIX
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!.
Q-8
Upper 16 bits —
envp
Q-7
Lower 16 bits —
envp
Q-6
Upper 16 bits —
argv
Q-5
Lower 16 bits —
argv
Q-4
argc
$UPPERCASEINTRINS
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.
$UPPERCASESEARCH
Tells SPLash! that intrinsic file procedure names in the SYSINTR- format
should be upshifted to uppercase.
$USLINIT
This option is quietly ignored (irrelevant for native mode programs on
MPE/iX).
$VARIABLEINTRINS
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.
! Declaration ! Variable? Mask passed? intrinsic fopen; ! Yes No intrinsic (myintrin) foo; ! Yes No $variableintrins intrinsic (myintrin) fum; ! Yes YES! $novariableintrins intrinsic (myintrin) fie, ! Yes No fff; ! No No procedure test (...); option external, splash, ! Yes Yes variable; procedure hpfopen (...); ! Yes No option external, intrinsic, extensible, variable, native, nocc; |
$VERSION ["text"]
VERSION "text.......text" is nearly identical to
$COPYRIGHT, but all of the text is emitted via ".VERSION"
assembler directives.
Example:
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.
Testing
Useful for testing and debugging your program
Extensions
Available only in SPLash!
This section explains how the Architected Interface (AIF) intrinsics
are used in SPLash!, and how to troubleshoot common problems.
AIF Usage from SPLash!
Several files have been provided to assist you in making AIF calls
from a SPLash! program. These files are located in the AIF group in
the SPLASH account.
The file named AIFOSX contains example code that shows
how to call the AIF:OS intrinsics: AIFACCTGET, AIFPROCGET,
and AIFFILEGGET. For each intrinsic call, several `items'
were requested to demonstrate the use of the various
parameters.
The file named DEFS contains a few global declarations
for calling AIFs and also includes several intrinsic
declaration files. All of these files are used by the
example code in the file named AIFOSX.
The file EXAM9 is example 9 from the AIF intrinsic manual,
AIFSYSWIDEGET section, rewritten in SPLash!.
AIF Data Structures
The most common problem that occurs when calling AIFs
from SPLash! is declaring the itemnum_array, item_array,
and itemstatus_array. Using the following format is
the best way to prevent the declaration problem.
equate
num'of'items = 10; ! USER DEFINABLE
virtual long array
item'array(0:num'of'items);
virtual double array
itemnums(0:num'of'items),
item'status(0:num'of'items);
logical
status'info,
status'subsys;
double
overall'status = status'info;
SPLash! offers two procedures for altering normal program flow. These
procedures are the SETJMP and LONGJMP procedures. Like their C
counterparts, these procedures are used to alter the normal function
call return sequence.
Add the following
external declarations
to your program. Or,
include the file
SETJMP.EXT.SPLASH
.
procedure splash'longjmp(jumpinfo'd,rslt);
value rslt;
double rslt;
double array jumpinfo'd;
option native, nocc, external;
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:
$VIRTUALGLOBAL
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".
$WARN
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.
$set X9 = ON
$X2 = OFF
...
$IF X2=ON
...
$IF X2=OFF
...
$IF
$XREF
Instructs SPLash! to provide procedure and variable cross-reference
information in the list file.
(top) (index)
$Option Default & Function Chart
Optimize
Selecting this option can improve performance
$option
Default
Optimize
Testing
Extensions
ADDRARITHMETIC
ALLOW
ADR
NOADR
ALIGN
NOALIGN
ALIGNED32
NOALIGNED32
ALIGNED32ALL
NOALIGNED32ALL
ALLOCQ
ALLOCQ
ALLOWBYTES
NOALLOWBYTES
ASMCOMMENT
ASMCOMMENT
ASMCOPYRIGHT
ASMCOPYRIGHT
BASE
OCTAL
BIGDIRECT
NOBIGDIRECT
BIGPROGRAM
NOBIGPROGRAM
BREAK
NONE
CARRY
IGNORE
CC
CC
CCINTRINS
CCINTRINS
CHECKSTACK
NOCHECKSTACK
CLEANFOR
CLEANFOR
CODE
NOCODE
COERCE
COERCE
COPYRIGHT
COPYRIGHT ""
CSTRINGS
NOCSTRING
DEBUG
NODEBUG
DEBUGATEND
NODEBUGATEND
DEFINE
NODEFINE
DIRECT
NODIRECT
DL = #
DL=0
ECHO "text"
ECHO ""
EDIT
ERRORS = #
ERROR=100
EXTERNAL
NATIVE
FASTMOVE
NOFASTMOVE
FOLLOW = #
GENCODE
GENCODE
GENSTAT
GENSTAT
HARDWARN
NOHARDWARN
IF X#=
ON or OFF
IMPORTDB
NOIMPORTDB
INCLUDE filename
INFO
INFO
INNERLIST
NOINNERLIST
INTERNAL
NATIVE
LINES=#
LINES=60
LIST
LIST
LOWERCASEINTRINS
LOWERCASEINTRINS
LOWERCASESEARCH
NOLOWERCASESEARCH
MAIN
MAP
NOMAP
MAPBYTE
NOMAPBYTES
MPE "text"
MPE ""
MILLIMOVE
NOMILLIMOVE
MILLISCAN
NOMILLISCAN
NATIVE
NATIVEONLY
NATIVEONLY
NEGX
NEGX
NEVERLIST
NONEVERLIST
NEWDLDB
NONEWDLDB
NMPCAL
NMPCAL
OBISMAIN
NOOBISMAIN
OBVARS
"obname"
OLDREALS
NOOLDREALS
OPTMOVE
OPTMOVE
OVERFLOW
IGNORE
PAGE
PAGE
PASCALIDS
NOPASCALIDS
PHASE
POP
PP
NOPP
PPC
NOPPC
PPEXPANDINTRINS
NOPPEXPANDINTRINS
PPSHORTPTRS
NOPPSHORTPTRS
PRIVILEGED
PSTRINGS
NOPSTRING
PUSH
QUICK
NOQUICK
REGVARS
SAMESIZEWARN
NOSAMESIZEWARN
SEGMENT
SEGMENT=""
SET X#=
ON or OFF
SOURCE
SOURCE
SPLASH
SPLASHEXT
NOSPLASHEXT
SPLASHINTRINS
NOSPLASHINTRINS
SPLASHG
SPLASHG
STACK
400
STATISTICS
NOSTATISTICS
STMT
NOSTMT
SUBPROGRAM
NOSUBPROGRAM
SUBRNAMES
NOSUBRNAMES
SUPPRESS = #
NOSUPPRESS
SYMLEN = #
SYMLEN for NM
SYSINTR
SYSINTR for NM
TESTSP
NOTESTSP
THIRTY
TP
TITLE "text"
TITLE=""
TRACE
TRACEPCAL
TRACEPCAL
TRY
NOTRY
TWENTY
ULIST
UNIX
NOUNIX
UPPERCASEINTRINS
NOUPPERCASEINTRINS
UPPERCASESEARCH
NOUPPERCASESEARCH
USLINIT
VARIABLEINTRINS
NOVARIABLEINTRINS
VERSION
VERSION=""
VIRTUALGLOBAL
NOVIRTUALGLOBAL
WARN
WARN
X#=
OFF or ON
XREF
NOXREF
(top) (index)
Architected Interface
Another commonly used structure is as follows:
(top) (index)
Non-local Jump Constructs
logical procedure splash'setjmp(jumpinfo'd);
double array jmupinfo'd;
option native, nocc, external;
if splash'setjmp(jumpinfo'd) <> 0 then
! get here on direct call
else
! get here from call to splash'longjmp
splash'longjmp(jumpinfo'd,1)
link from=$oldpass,jumpero.milli.splash;to=myprog
(top) (index)
7 Using XREF
Introduction
:file text=ascii.inc.splash :run xref.pub.splash |
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.
Control-Y
begin ! SPL |
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. begin . . . ! Standalone code (No calls to SPLASH procedures) end; |
IEEE format - 64 bits HP3000 format - 64 bits
Max: 1.8E308 Max: 1.2E77 Min: -1.8E308 Min: -1.2E77 Accuracy: 15.9 digits Accuracy: 16.5 digits
Bits Field Usage Bits Field Usage
0 00:01 Sign bit 0 00:01 Sign bit 1..11 01:11 Exponent 1..9 01:09 Exponent 12..63 12:52 Mantissa 10..63 10:54 Mantissa
Exponent Exponent
Excess 1023 Excess 256 $7FF = NAN (Not A Number) or Infinity
Zero Zero
all bits 0 all bits 0
$control nooldreals ! not needed, default $control subprogram, native begin real procedure add'ieee (r1, r2); value r1, r2; real r1, r2; begin add'ieee := r1 + r2; end; end. |
Source file SUB2:
$control oldreals $control subprogram, native begin real procedure add'classic (r1, r2); value r1, r2; real r1, r2; begin add'classic := r1 + r2; end; end. |
Source file OB:
begin real x, y; |
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:
LINK FROM=sub1.obj, sub2.obj, ob.obj; to = ob.pub
This section describes the data types supported by SPLash!, and their equivalences in other native mode languages.
The base SPLash! data types are:
byte
8 bits. A byte can be thought of as holding an ASCII
character or a numeric value in the range 0..255.
logical
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).
integer
16 bits. An integer is a numeric value in the range
-32768..32767.
double
32 bits. A double is a numeric value in the range
-2147483648..2147483647.
real
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.
long
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.
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.
SPLash! Pascal/iX C/iX note:
byte char char #6 integer shortint short double integer int (or long) real real real long longreal double array array array #1 pointer ^^ * #4 fullvirtual ptr ^^$extnaddr$ ^^ procedure procedure ? logical "0..65535" unsigned short #2Inexact:
"double array" longint ? #3 "long array" longreal ? #3 "byte array" string - "double" set ? "byte array" record structNo mappings known:
label - - #5
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.
value
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"
"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"
"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"
"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:
fullvirtual byte pointer ptr; procedure hpfopen ( ..., item5, uany5, ...); value item5, uany5; integer item5; virtual byte pointer uany5; ... hpfopen ( ... , 21, ptr, ...);In the above call, SPLash! would try to pass the VALUE in ptr instead of the address of ptr. A workaround is:
double ptr'dummy = ptr; ... hpfopen ( ..., 21, ptr'dummy, ...);
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.
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 sourceStep 3: Intercept Intrinsic calls on the HP9000 using the C Intercept Library$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);
end.
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
! 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.exeThe C Intercept Library! hello.exe is the ported SPL!
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.
begin
...
$if x8=off
intrinsic print, quit, ...
$else
$include mpeint.ext.splash ! external declarations
$endif
$native
$if x8=on
$unix
$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:
CCODE FREADDIR PRINTFILEINFO FCHECK FWRITE QUIT FCLOSE FWRITEDIR READX FOPEN HPSETCCODE TERMINATE FREAD PRINT
Plus, the following general purpose functions:
mpeint_erase_fid, mpeint_filename_to_unix, mpeint_initialize
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.
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.
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.
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:
$try beginprocedure p1; begin ... ! Error here handled by mainline recover block. try begin ... ! Error here handled by p1 recover block. end recover begin ... ! Error here handled by mainline recover block. end; ... ! Error here handled by mainline recover block. end;
!mainline ... ! Error here causes program abort. try begin ... ! Error here handled by mainline recover block. p1; end recover begin ... ! Error here causes program abort. end; ... ! Error here causes program abort. end.
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.
ESCAPECODE Function
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:
procedure foo; begin ... ... ... try ... ... ...
recover ... ... ... ... ... ... end
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.
SYSTEM ESCAPE CODES
The following list can be found in
SYSESC.INC.SPLASH
, which is
a subset of the information from
PASESC.PUB.SYS
(provided by HP):
Value (decimal)
Name
200 CHKT_CHKF
524488 PARA_STACK_OVERFLOW
590024 UNK_COND_TRAP
655560 PTR_ARTIH_ERROR
721096 NILL_PTR_DEREF
786632 RANGE_ERROR
852168 FP_INV_OPERATION
917704 FP_DIV_ZERO
983240 FP_OVERFLOW
1048776 FP_UNDERFLOW
1114312 INEXACT_RESULT
1179848 DEC_DIV_ZERO
1376456 INV_DECIMAL_DIGIT
1441992 INV_ASCII_DIGIT
1507528 DECIMAL_OVERFLOW
1573064 DDIV_ZERO_3000
1638600 D_UNDERFLOW_3000
1704136 D_OVERFLOW_3000
1769672 INTEGER_OVERFLOW
1835208 F_OVERFLOW_3000
1900744 F_UNDERFLOW_3000
1966280 INT_DIV_ZERO
2031816 FDIV_ZERO_3000
3342536 ILL_INSTRUCTION
3408072 BUS_ERROR
3408072 DATA_MEM_PROT_TRAP
3408072 INSTR_MEM_PROT_TRAP
3473608 SEG_VIOLATION
3473608 ILL_POINTER
3539144 UNK_HPUX_SIGNAL
(top) (index)
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.
PROBEW
Determines whether write access to a given address is
allowed.
MTSP
Moves a value from a general register to a space
register.
MFSP
Moves a value to a general register from a space
register.
RSYSG
Reads a 32-bit value from the system globals area.
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.
Affect: R8 := $c0000000 (address of system globals)
R8 := [R8 + #]; (fetch 32 bits)
tos := R8;
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:
double real'memory'size
assemble (rsysg $DEC; std real'memory'size);
Or,
real'memory'size := double assemble (rsysg $DEC);
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.
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:
virtual pointer kso9;
assemble (kso 9; std kso9; ddel);
Classic instructions
The following assembler instructions are also available.
SCAL
Subroutine call.
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.
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.
Intrinsic Name Why SPLash flags it
DATE'LINE Apostrophe has been removed from the name.
DLSIZE Since SPLash! programs maintain their own
CM stack, using this intrinsic can cause
unexpected results. Allegro provides a replacement
DLSIZE call to solve this problem. See
DLSIZE.INC.SPLASH
for operational details.
EXTIN' & INEXT' New name, and IEEE rather than the Classic
floating point.
GETHEAP Change in functionality.
LOADPROC Unexpected results. See the file
LOADPROC.INC.SPLASH
for a replacement routine.
(Dynamically load a CM SL procedure and any
external procedures it references).
SWITCHDB and EXCHANGEDB
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.
The SPLash! message catalog may be found in the file
SPLCAT.PUB.SPLASH
.
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.
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.
ABORT
Note
—At entry to the debugger, "current node" has
this value.
0 = plain, 1 = stub, 2 = entry, 3 = exit
4 = proc, 5 = subr, 6 = ob'entry
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.
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.
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:
nmdebug> dcmq (offset,len)
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.
ms
Macro Definitions
mac dcmdb (offset, words=1) {dcm r4+offset*2, words}
mac dcmq (offset, words=1) {dcm r5+offset*2, words}
mac dcms (offset, words=1) {dcm r6+offset*2, words}
/* Usage: get16 (addr) --> returns 16-bit value starting at specified
/* EVEN byte address (odd addresses rounded down)
mac get16 (virtaddr) {
loc xxx = [virtaddr];
if (off (virtaddr) band 3) >= 2 then loc xxx = xxx band $ffff
else loc xxx = xxx >> #16;
return u16 (xxx)}
mac leftright (xx) {if (xx mod 4)=0 then wl "Look at left 16 bits" &
else wl "Look at right 16 bits"}
mac odd (n) {return (n band 1)}
mac dcm1 (addr) {
loc xxx:U16 = 0;
if odd(addr >> 1) then loc xxx = [addr] band $ffff
else loc xxx = [addr] >> #16;
wl xxx:"F$", " ",xxx:"F#", " ",xxx:"F%", " ",
xxx:"A" }
mac dcm (addr, words = 1) {
while words > 0 do {
dcm1 (addr); loc addr = addr + 2; loc words = words - 1}}
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.
/* 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,"#")}}
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]
Examples:
CMDLIST
Lists all commands
CMDLIST @Z@
List all commands with a "Z" in the name
CMDLIST @R@, window List all window commands
with an "R" in the name
CMDLIST @Z@, , ALL Print Help text for
commands with a "Z" in the name
FUNCLIST
funcpattern [catogory] [what]
Examples:
FUNCLIST
Lists all functions
FUNCL @Z@ List all
functions with a "Z" in the name
ENVLIST
envpattern [category]
Examples:
ENVLIST Lists most environmental
variables
ENVLIST , STATE List the "state" oriented
variables
ENVLIST , ALL List all environmental variables
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".
The DISPLAY commands display information on your screen in a variety
of formats.
DV
address [#words] [base] [recw] [recb]
The base parameter defaults to the current output base. Possible
values include the following:
$ or H Hex output
# or D Decimal output
% or O Octal output
A ASCII output (4 bytes, then a blank)
B Both Hex and ASCII output
C Code output (disassembled NM code)
S String output (one long continuous string of
ASCII output)
Examples:
DV DP+8
Display first global Pascal/iX variable.
DV [DP+8], 3 Fetch a 32-bit address
from DP+8, then display 3 words of
memory at that address.
DDB
dbaddr [#halfs] [base]
DR
dr [register]
Examples:
DR Displays all registers
CM; DR Displays all CM "registers"
CM; DR; NM; DR Displays all registers for
both modes.
These instructions are useful for controlling the execution of your
program.
Ss
[#instructions]
nmdebug > B pc+8
By default, breakpoints are permanent (for the life of the process).
To setup a one-shot breakpoint (called temporary breakpoint in MPE V),
use the following command:
nmdebug > B pc+8,-1
The count option, which defaults to 1, means: pop up into the
debugger every "count" times through this point. Thus, if a FOR loop
had a breakpoint with a count of "2", then every second time through
the loop you would enter the debugger.
The LOUD/QUIET options (default is LOUD) tell the debugger whether
it should announce the fact that you just entered Debug/iX.
The cmd option (default is none) is a command to be executed when
you pop up into the debugger. If the "C" command is not part of the
commands executed, then you will remain in the debugger after
the commands execute.
Examples:
1
To set a breakpoint at the entry to FOPEN use:
2
To set a breakpoint at address 5100 in my program use:
3
To set a temporary breakpoint at 24 bytes beyond the
"PROGRAM" start use:
4
To set a breakpoint 8 bytes after the current program counter,
and conditionally continue execution based on the value of a
virtual memory location use:
BD
[@]
C
(and Exit)
ABORT
SET CRON
For Example:
nmdebug > s ! single step
nmdebug > <cr> ! single step
nmdebug > <cr> ! single step
nmdebug > <cr> ! single step
Usage: assemble (PROBER (sr#, gr#), gr#, gr#);
Usage: assemble (PROBEW (sr#, gr#), gr#, gr#);
Usage: assemble (MTSP gr#, sr#);
Usage: assemble (MFSP sr#, gr#);
Usage: assemble (RSYSG #);
Usage: assemble (KSO #)
fullvirtual pointer kso9;
double kso9'space = kso9,
kso9'offset = kso9 + 2;
assemble (kso 9; std kso9'offset; std kso9'space);
or
assemble (kso 9); @kso9 := tos;
Usage: assemble (scal 0);
Opcode Meaning
LDEA Load Double from Extended Address (bank.offset)
LSEA Load Single from Extended Address (bank.offset)
LST Load from System Table
MABS Move Absolute ... moves from bank.offset to bank.offset
MDS Move Data Segment ... moves from one data segment to another
MFDS Move From Data Segment (into stack)
MTDS Move To Data Segment (from stack)
PLDA Privileged Load Absolute (like LSEA, but from bank 0)
PSTA Privileged Store Absolute (like SSEA, but to bank 0)
SDEA Store Double to Extended Address (bank.offset)
SSEA Store Single to Extended Address (bank.offset)
SST Store to System Table
(top) (index)
Appendix B : Intrinsic Changes
Intrinsic Changes
(top) (index)
Appendix C : Compiler Messages
(top) (index)
Appendix D : SPLash! Debugger
SPLash! Debugger
SPLash! Debugger Commands
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.
Continue
Exits the debugger, just like the slash (/) command.
CURrent
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:
DAD 804
DAD
TREE
DEBUG
Calls Debug/iX, the HP debugger.
DEBUGGER text
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.
Exit
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)
HELP
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.
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 ] [...]
See SUPPRESS.
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.
PRIORITY [CS | DS | ES]
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.
PSCREEN
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.
Resume
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.
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
STATistics
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.
TERMinate
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).
WALK
"Walks" all the nodes of the tree and then reports
on it's findings.
WANTdebug
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
:mpecommand
Calls the COMMAND intrinsic with the rest of the input.
/ (forward slash)
Exits this debugger.
(top) (index)
Appendix E : SPLash! & Debug/iX Macros
Introduction
SPLash! Macros for DEBUG
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.
: run progname;debug <<<<<<< start debug
nmdebug> use splash.macro <<<<<<< load splash
macros
dcmdb = dump db relative
dcmq = dump q relative
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
The armall, disarmall, and untrap macros are useful when a SPLash!
program is compiled with one (or more) of the $BREAK= options.
/* Usage: dcmdb (4, 3) --> Displays mem at: DB+4, DB+5, DB+6
/* Usage: dcmq (-3, 4) --> Displays mem at: Q-3, Q-2, Q-1, Q
/* Usage: dcms (-4) --> Displays mem at: S-4
mac armall {trap trace arm; trap}
mac disarmall {trap trace disarm; trap}
mac untrap (trapname) {trap !trapname disarm; trap !trapname}
(top) (index)
Using DEBUG on MPE/iX
The CMDLIST command lists all of the commands known to Debug/iX.
The FUNCList command lists all of the built-in functions known to
Debug/iX.
Debug/iX has a set of about 200 predefined variables you can access.
These variables are called "environmental variables." All of the
variables can be "read", and most can be changed (written). Some
require that the user have PM to change their values. The category
parameter selects the type of environmental variable you want to have
listed. The default is NOSTATE, which excludes variables that refer
to hardware registers (e.g., R21, DP, SR1).
(top) (index)
Displaying Data
The Display Virtual (DV) command displays the contents of virtual
memory starting at the specified address. Note that DV rounds that
address down to a multiple of 4 at the start. The
#words
parameter is the number of 32-bit words to be displayed; the default
is 1.
The DDB command displays the specified number of 16-bit words from
the CM stack starting at the desired DB relative address.
DQ
qaddr [#halfs] [base]
DS
saddr {#halfs] [base]
The DQ and DS commands display data from the CM stack Q-relative and
S-relative, respectively.
If used by itself, Display Registers (DR) displays all of the
"hardware" registers for your current execution mode. To see the
registers for the other mode, combine with the CM and NM commands.
(top) (index)
Singlestep & Breakpoint
B
address [count] [<LOUD] | QUIET>] [cmd]
The Singlestep command (S or s) executes the desired number of
instructions and then returns to the debugger (assuming the
program has not terminated prior to that point). You may return
to the debugger immediately, whenever a breakpoint is encountered.
The Breakpoint instruction establishes a breakpoint at the
specified address. For example, to setup a breakpoint at the
second instruction after the current program counter (in NM) you
would use the following command:
nmdebug > b FOPEN
nmdebug > b 5100
nmdebug > b PROGRAM+24,-1
nmdebug > b pc+8,,,{if [dp+8]<>0 then c}
The BD command deletes breakpoints. If "@" is specified, all
breakpoints are deleted. If a number is specified (for example BD 3),
then that specific breakpoint is deleted. If no parameters are
specified, Debug/iX will prompt for permission to delete each breakpoint
(the default answer is NO).
(top) (index)
Miscellaneous Debug/iX Commands
The Continue command resumes executing your program.
Aborts your program, immediately. If you have PM and are
debugging inside of system code, the debugger will not let you
abort if your process is critical or hold a SIR.
Tells Debug/iX that, until cancelled, an empty line of input
means: repeat the last non-empty line. One application for this is in
single stepping.
SET CROFF
WHELP
Disables the SET CRON command.
WON
Displays several screens of help text about windows.
WOFF
Turns window mode on.
RED
Turns window mode off.
VW virtaddr [name]
Redraws the windows, useful if your program sent an escape
sequence that cleared the screen.
VK [virtualwindow#]
Opens a window looking at the specified virtual address. When
windows are on (WON), this window will appear after the default
windows.
Kills a virtual window (deletes it from the window display and
forgets about it).
(top) (index)
Appendix F : 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 stmtMYCOMMAND Intrinsicbegin
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;
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/20LOADPROC Intrinsic! 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;
begin
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);
debug;
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;
nextparm:
scan pntr while crblank, 1; assemble (dup, dup); @pntr := tos; start := tos; tos := 0; go scanalphnum;
doblank:
scan pntr while crblank, 1; @pntr := tos; if < then go checkfunny;
dospecial:
tos := tos lor %40;
scanalphnum:
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.
checkfunny:
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;
exit'cce:
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.inc 88/12/07integer 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!
begin
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'proc:
end <<loadproc'nm proc>>;
This section briefly reviews the HP Precision Architecture hardware and MPE/iX operating system.
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:
A reduced number of instructions (HP Precision
Architecture has 140,
while the earlier HP3000 design has over 250), most of which
execute in one clock cycle. Instructions fall into the general
categories of load, store, branch, add, subtract, and control.
Further, they are implemented in hardware in order to speed
execution.
Instructions have a fixed size, which simplifies
their execution.
Memory is accessed via load and store instructions.
All other
instructions act solely upon registers.
The design facilitates pipelining, which increases
instruction
throughput.
Virtual memory is very large, with 48-bit
addressing capability.
Memory-mapped I/O makes I/O drivers easier to write
and
enables the user to perform direct I/O functions.
High-performance cache memory speeds up access to
both data and code.
Optimizing compilers streamline code generation.
Multiple coprocessors increase performance.
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.
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.
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.
Comparing MPE V and MPE/iX
MPE V-Based HP3000s
DB Bank Register.
As explained above, memory
is divided into banks of 128K bytes. The DB Bank register
identifies the memory bank within which the DB register
currently points.
S Bank Register.
This bank register identifies
the memory bank that contains the stack.
DB Register.
The DB register acts as a zero point
for accessing a program's data.
DL (Data Limit) Register.
This register points to
the area of the stack that is the lowest addressable memory
address available to the user.
Q Register.
This register provides a moveable
base (zero point) for a procedure's data area.
S Register.
The S register points to a word
called Top of Stack (TOS), where calculations are performed.
Z Register.
This register identifies the actual
physical top of the stack area in memory.
PB Bank Register.
This register contains the memory
bank number of the currently executing code.
PL (Program Limit) Register.
Marks the end of the
currently executing code segment.
P (Program) Register.
Points to the currently
executing machine instruction.
Status Register.
This register contains many
fields that describe the current state of the machine.
X (Index) Register.
This register is used by
many load and store instructions as an aid in indexed addressing.
CIR (Current Instruction Register).
This register
contains the actual value of the executing machine instruction.
(top) (index)
MPE/iX-Based HP3000s
Loading from Register GR0 always loads a zero;
storing to
Register GR0 discards the stored data.
Register GR1 is used as the target of the ADDIL (Add
Immediate Left) instruction.
Register GR31 receives the branch target address
when
executing the BLE (Branch and Link External) instructions.
GR2 is referred to as the Return Pointer (RP). By
convention,
it contains the address to return to when completing a procedure
call.
GR23 through GR26, sometimes referred to as ARG3
through
ARG0, are used to store the first four parameters when calling
a procedure.
GR27 is called the DP register and serves as a base
address
for a process's global data.
It is analogous to the DB register on the
MPE V-based HP3000.
GR28 and GR29, known as RET0 and RET1, contain
procedure
return values.
GR30 serves as the Stack Pointer (SP). It is
roughly equivalent
to the S register in the MPE V-based HP3000. It is used to delimit
the top of the current stack.
The IA (Instruction Address) registers keep track
of the address
of the currently executing instruction. They are analogous to the
MPE V-based HP3000's P register.
The PSW (Processor Status Word) is a special
register similar
to the status register of the MPE V-based HP3000.
Space registers SR0 through SR7 are used to keep
track of
the space numbers used to construct addresses.
(top) (index)
Glossary
Address
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.
Branch
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.
Byte
A byte is 8 bits.
CISC
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.
Debug/iX
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
Global is typically used to refer to variables declared in the
outer block of a SPLash! or Pascal/iX program.
GLOBAL and EXTERNAL
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).
Halfword
A halfword is 16 bits.
Linker
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.
Microcode
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.
Pipelining
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.
SOM
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.
Stack
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.
Word
A word is 32 bits.
(top) (index)