121636-003 PLM-86 Users Guide Oct82
121636-003 PLM-86 Users Guide Oct82
121636-003 PLM-86 Users Guide Oct82
Literature Department
Intel Corporation
3065 Bowers Avenue
Santa Clara, CA 95051
Intel Corporation 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. Intel Corporation assumes
no responsibility for any errors that may appear in this document. Intel Corporation makes no commitment
to update nor to keep current the information contained in this document.
Intel Corporation assumes no responsibility for the use of any circuitry other than circuitry embodied in
an Intel product. No other circuit patent licenses are implied.
Intel software products are copyrighted by and shall remain the property of Intel Corporation. Use, dupli-
cation or disclosure is subject to restrictions stated in Intel's software license, or as defined in ASPR
7-104.9(a)(9).
No part of this document may be copied or reproduced in any form or by any means without the prior
written consent of Intel Corporation.
The following are trademarks of Intel Corporation and its affiliates and may be used to identify Intel
products:
BXP Insite iSBC MULTICHANNEL
CREDIT intel iSBX MULTIMODULE
i Intelevision iSXM Plug-A-BubbIe
PICE Intellec Library Manager PROMPT
ICE Intellink MCS RMX/80
iCS iOSP Megacbassis RUPI
im iPDS MICROMAINFRAME System 2000
iMMX iRMX MULTI BUS UPI
A711/882/5K DD
ii
REV. REVISION HISTORY DATE
iii
HOW TO USE THIS MANUAL
This manual gives instructions for programming in PL/M-86 and for using the
PL/M-86 compiler to prepare programs for iAPX 86 microcomputer systems. It is
primarily a reference manual for use when you are writing or compiling
PL/M-86 programs; however, it also contains some introductory information to help
you familiarize yourself with PL/M-86 as you start to use it.
The manual assumes you are familiar with basic programming concepts, including
structured programming. The manual, however, does define the language completely,
assuming no prior knowledge of PL/M-86.
Following the description of the language, the manual provides instructions for
compiling your PL/M-86 programs, linking the compiled code, and executing the
final program. It also explains how to interpret compiler output, including error
messages.
Manual Organization
This manual contains four kinds of information:
• Introductory and general reference information, including installation instruc-
tions
• Language information, for when you are programming in PL/M-86
• Operating instructions for the compiler and descriptions of compiler controls
• Interfacing information you need if you supply some of your own systems software
in place of that supplied by Intel (e.g., a non-Intel operating system), or if you
are interfacing PL/M-86 modules to modules written in other languages such as
ASM86.
If you are a manager evaluating PL/M-86 to determine whether it fits your needs,
you will find most of the information you need in Chapter 1, which is an overview of
the product.
To get started with PL/M-86, first read this Preface (How to Use this Manual) and
Chapter 1. (If you are familiar with assembly languages but not with high-level
languages, see section 1.2 for a discussion of the advantages of a high-level language
such as PL/M.) Then install the compiler (see instructions in the appendix for your
specific operating system) and try compiling, linking, and running the sample program
at the end of Chapter 1 to verify that the software operates properly.
After that, if PL/M is a new language to you, study and run the sample program in
Chapter 12. Finally, skim through the manual from Chapter 2 to the end and try
writing and running a few programs of your own. Once you have become familiar
with PL/M-86, you will find this manual useful as a complete reference. For a quick
reference, see the PL/M-86 Pocket Reference (order number 121622).
v
If you wish to transport existing PL/M-80 programs to your iAPX 86 application
system, refer to Appendix D for a list of the differences between PL/M-80 and
PL/M-86. This appendix indicates the areas of your programs that may require
modification.
Once you have coded your programs, you are ready to compile, link, and run them.
Refer to Chapter II for information on how to use compiler controls; refer to your
specific host-system appendix for compiler operating instructions. Chapter 14 helps
you interpret error messages you may receive when compiling or running your
programs. For a detailed explanation of the linking process, refer to the iAPX 86
Utilities User's Guide (order number 121616).
If you are coding some of your application software in another language such as
ASM86, refer to Appendix F for the information you need. If you are interfacing to
your own operating system or providing your own file/device drivers, refer to Appen-
dix G for instructions.
Notational Conventions
Section Numbers
All chapters and appendixes are section-numbered for easy cross-referencing. For
instance, heading number 5.3 denotes Chapter 5, section 3. When the text of one
section refers to another section, the reference is made by number; e.g., "as described
in 7.1." Figures and tables are also numbered to aid in cross-referencing; e.g., "in
table 3-1," "see figure 14-1."
Interactive computer dialogue in this manual consists of commands you enter, which
are immediately echoed on the console display, and the text displayed by the opera-
ting system, the PL/M-86 compiler, and other Intel-supplied programs. The text you
enter is shown in reverse type (white on a black background), and the text displayed
by Intel programs is shown in normal black type. The notation (cr) stands for the
RETURN key on the console keyboard.
Syntax Notation
In the syntax notation for this manual, the following conventions apply:
• Keywords, letter symbols, and punctuation symbols that you use verbatim in your
programs-the terminal symbols of the language-are represented in monospace
type, in which every character has the same width, just as they do in output
media such as CRT console displays and printouts. All letters in terminal symbols
are shown in uppercase in the notation; however, you may use either uppercase
or lowercase for these symbols in your programs. For example:
E WHILE PROCEDURE
( TO LITERALLY
DO END
are terminal symbols.
• Terms standing for language elements or constructs that are defined elsewhere
in this notation-in other words, nonterminal symbols-are represented in itali-
cized lowercase letters in non-monospace type, in which the width of a character
varies. For example:
digits variable
sign expression
binary-digit statement
specifies that the first set of digits, the. symbol, and the second set of digits must
be concatenated, with no blanks between them. Likewise, the E symbol, the sign
if included, and the third set of digits must be concatenated. Blanks are permitted
only between the second set of digits and the E symbol.
• Optional constructs are enclosed in square brackets. For example, in the construct
represented by
the first and second sets of digits and the . symbol are required, and the entire
part following the second set of digits is optional. If this optional part is included,
the sign may still be omitted.
• Optional constructs that can be repeated a number of times are marked by a
three-dot ellipsis following the closing square bracket. For example:
digits
binary-digit [binary-digitj ... B
octa/-digit [ octal-digitj ... Q
hex-digit [hex-digitj ... H
indicates that the construct described may have anyone of the four forms listed
between the large braces.
• Text enclosed between the character sequence /* and the sequence * /, when
these symbols are in light, non-monospace type, is a prose definition of the given
construct. Such definitions are used when symbolic definitions would be more
cumbersome. For example:
vii
• The start of a new line in the notation does not mean you must start a new line
at that point in your program; however, you may do so for readability. For
example, when you use the construct:
you need not include a carriage return after the second expression, but, in many
programs, doing so makes the statement more readable.
(See Appendix C for the BNF notation for the PL/M-86 language.)
viii
CONTENTS I
CHAPTER 1 PAGE PAGE
INTRODUCfION Based Variables ......................................................... 3-15
Product Definition .... ............. ....... ........ ..... ..... ... ........ 1-1 Location References and Based Variables ........... 3-17
The PL/M-86 Language ........................................... 1-1 The AT Attribute ...................................................... 3-17
Using a High-Level Language .............................. 1-1
Why PL/M? .......................................................... 1-2 CHAPTER 4
The Structure of a PL/M-86 Program ..................... 1-2 EXPRESSIONS AND ASSIGNMENTS
PL/M-86 Statements ................................................ 1-3 Operands ................................................. ...... ............. 4-1
Declaration Statements ......................................... 1-3 Constants ............... ..... ............................ ................ 4-1
Executable Statements ........... ............... ................ 1-4 Variable and Location References ........................ 4-2
Built-In Procedures and Variables ........................ 1-4 Subexpressions ....................................................... 4-2
Expressions .......... ,. .......... ..... ... .... ............... ..... ....... 1-4 Compound Operands ............................................. 4-2
Input and Output ................................................... 1-5 Arithmetic Operators '................................................ 4-3
The Program Development Process .......................... 1-5 The +, -, *, and / Operators ............................. 4-3
An Introductory Sample Program .... ........................ 1-6 The MOD Operator ............................................... 4-4
Relational Operators ................................................. 4-4
CHAPTER 2 LogicalOperators ...................................................... 4-5
LANGUAGE ELEMENTS Expression Evaluation ............................................... 4-6
PL/M-86 Character Set ........................................... 2-1 Precedence of Operators: Analyzing an
Tokens, Separators, and the Use of Blanks .............. 2-2 Expression .............................. ........ ................ 4-6
Identifiers and Reserved Words ............................... 2-3 Compound Operands Have Types ........................ 4-8
Constants ................................................................... 2-3 Relational Operators Are Restricted .... ................ 4-9
Whole-Number Constants ..................................... 2-3 Order of Evaluation of Operands ......................... 4-9
Floating-Point Constants ............... ........................ 2-4 Choice of Arithmetic: Summary of Rules ............... 4-10
Character Strings .................................................. 2-5 Special Case: Constant Expressions ..... ................ 4-11
Comments .................................................................. 2-5 Assignment Statements ............................................. 4-12
Implicit Type Conversions ....................... ............. 4-13
CHAPTER 3 Constant Expression ................. .......... ........ ...... ..... 4-13
DATA DECLARATIONS, TYPES, AND Multiple Assignment ............................................. 4-14
BASED VARIABLES Embedded Assignments ........................................ 4-14
Variable Declaration Statements .............. ..... ........... 3-1
Examples ................................................................ 3-2 CHAPTERS
Results .................................................................... 3-3 ARRAYS AND STRUCTURES
Combining DECLARE Statements ..................... 3-3 Arrays ........................................................................ 5-1
Initializations ............................................................. 3-4 Subscripted Variables ........................................... 5-1
The Implicit Dimension Specifier .... ..... .... ..... ....... 3-6 Structures .................................................................. 5-2
Names for Execution Constants: The Use of Arrays of Structures .............................................. 5-3
DATA ............................................................. 3-6 Arrays Within Structures ...................................... 5-3
Types of Declaration Statements .............................. 3-7 Arrays of Structures with Arrays
Compilation Constants (Text Substitution): Inside the Structures ........................ ............. 5-3
The Use of LITERALLY ............................. 3-7 References to Arrays and Structures ....................... 5-4
Declarations of Names for Labels ........................ 3-8 Fully Qualified Variable References .................... 5-4
Results .. ............. ....... ................................... ........... 3-9 Unqualified and Partially Qualified
Declarations for Procedures ...... ............ ................ 3-9 Variable References ....................................... 5-4
Data Types ................................................................. 3-10
BYTE, WORD, and DWORD Variables: CHAPTER 6
Unsigned Arithmetic ..................................... 3-10 FLOW CONTROL STATEMENTS
INTEGER Variables: Signed Arithmetic ............ 3-11 DO and END Statements: DO Blocks ..................... 6-1
REAL Variables: Floating-Point Arithmetic ....... 3-11 Simple DO Blocks ................................................. 6-2
Examples of Binary Scientific Notation ............... 3-12 DO CASE Blocks .................................................. 6-3
POINTER Variables and Location References... 3-13 DO WHILE Blocks ............................................... 6-4
The @ Operator ............................................ 3-13 Iterative DO Blocks ............................................... 6-5
The "Dot" Operator ....... ....... ........................ 3-15 ~e IF Statement ...................................................... 6-7
SELECTOR Variables .......................................... 3-J5 Nested IF Statements ........................................... 6-8
ix
CONTENTS (Cont'd.)
Sequential IF Statements ..................................... . 6-10 Functions ............... ... .................. .... ..... ........... 9-11
GOTO Statements ................................................... . 6-il The SKIPB/SKIPW and SKIPRB/SKIPRW
The CALL and RETURN Statements ................... . 6-12 Functions ............ ....... .......................... ... ........ 9-11
The XLAT Procedure ........................................... 9-12
CHAPTER 7 The SETB and SETW Procedures ....................... 9-12
BLOCK STRUCTURE AND SCOPE Miscellaneous Built-Ins ............................................. 9-13
Names Recognized Within Blocks .......................... . 7-1 The MOVE Procedure .......................................... 9-13
Restrictions on Multiple Declarations ................. . 7-2 The TIME Procedure ............................................ 9-13
Extended Scope: The PUBLIC and The MEMORY Array.......................................... 9-14
EXTERNAL Attributes ................................. .. 7-4 The LOCKSET Function ...................................... 9-14
Scope of Labels and Restriction on GOTOs ........... . 7-6 Interrupt-Related Procedures ................................... 9-15
The SET$INTERRUPT Procedure ..................... 9-15
CHAPTER 8 The INTERRUPT$PTR Function ....................... 9-15
PROCEDURES POINTER and SELECTOR-Related Functions ..... 9-16
Procedure Declarations .8-1 The BUILD$PTR Function .................. ................ 9-16
Parameters ............................................................ . 8-2 The SELECTOR$OF Function ............................ 9-16
Typed Versus Untyped Procedures ..................... . 8-3 The OFFSETSOF Function .................................. 9-16
Activating a Procedure-Function References The NIL Function ................................................. 9-16
and CALL Statements ...................................... 8-4
Indirect Procedure Activation ............................. . 8-5
Exit from a Procedure: The RETURN Statement .. 8-5
The Procedure Body ................................................. . 8-6 CHAPTER 10
The Attributes: PUBLIC and EXTERNAL, PLfM-86 FEATURES INVOLVING
INTERRUPT, REENTRANT ....................... . 8-7 iAPX 86 HARDWARE
Interrupts and the INTERRUPT Attribute ....... . 8-8 iAPX 86 Hardware-Dependent Statements ............. 10-1
Activating an Interrupt Procedure The ENABLE and DISABLE Statements .......... 10-1
with a CALL Statement ............................... . 8-9 The CAUSE$INTERRUPT Statement ............... 10-1
Reentrancy and the REENTRANT Attribute ... . 8-10 The HALT Statement ........................................... 10-1
The iAPX 86 Hardware Flags .................................. 10-1
CHAPTER 9 Optimization and the Hardware Flags ................. 10-1
BUILT-IN PROCEDURES, FUNCTIONS, The CARRY, SIGN, ZERO, and PARITY
AND VARIABLES Functions ................ ... .......... ....... ....... ..... ..... ... 10-2
Obtaining Information About Variables ................. . 9-1 The PLUS and MINUS Operators ...................... 10-2
The LENGTH Function ..................................... .. 9-1 Carry-Rotation Functions ...................................... 10-3
The LAST Function ............................................. . 9-2 The DEC Function ................................................ 10-3
The SIZE Function ............................................. .. 9-2 The iAPX 86 Hardware Registers ............................ 10-3
Explicit Type and Value Conversions ..................... . 9-3 The FLAGS Variable ............................................ 10-3
The LOW, HIGH, and DOUBLE Functions ..... . 9-4 The STACKPTR and STACKBASE Variables.. 10-4
The FLOAT Function ......................................... .. 9-5 iAPX 86 Hardware I/O ............................................ 10-4
The FIX Function ................................................. . 9-5 The INPUT and INWORD Functions ................ 10-4
The INT Function ................................................ . 9-5 The OUTPUT and OUTWORD Arrays .............. 10-5
The SIGNED Function ........................................ . 9-6 The BLOCKINPUT and BLOCKINWORD
The UNSIGN Function ....................................... . 9-6 Procedures ...................................................... 10-5
The ABS and lABS Functions ............................ . 9-7 TheBLOCKOUTPUTandBLOCKOUTWORD
Shift and Rotate Functions ...................................... . 9-7 Procedures ...................................................... 10-5
Rotation Functions ROL and ROR ..................... . 9-7 The REAL Math Facility......................................... 10-6
Logical-Shift Functions SHL and SHR .............. . 9-8 Built-ins Supporting the REAL Math Unit ............. 10-8
Algebraic-Shift Functions SAL and SAR ........... . 9-8 The SET$REALSMODE Procedure ................... 10-8
String Manipulation Procedures .............................. . 9-9 The GET$REAL$ERROR Function ................... 10-8
The MOVB and MOVW Procedures .................. . 9-10 Saving and Restoring the REAL Status .............. 10-9
The MOVRB and MOVRW Procedures ............ . 9-10 The SAVE$REAL$STATUS Procedure ......... 10-9
The CMPB and CMPW Functions ..................... . 9-10 The RESTORE$REALSSTATUS
The FINDBjFINDW and FINDRB/FINDRW Procedure ................................ ........... ..... ... 10-10
x
CONTENTS (Cont'd.) I
CHAPTER 11 CHAPTER 13
COMPILER CONTROLS PLfM-86 EXTENDED
Introduction to Compiler Controls ... ...... ............ ...... 11-1 SEGMENTATION MODELS
The MOD86/MODI86 Control............................... 11-2 Introduction ......... .................. ..... ... ...... .... ...... ...... ... ... 13-1
The LEFIMARGIN Control,................................... 11-2 Extended Segmentation ........................................ 13-1
Object File Controls ................................ ............ ...... 11-3 Subsystems ................................................................ 13-2
INTVECTOR/NOINTVECTOR ........................ 11-4 Open and Closed Subsystems ............................... 13-3
OVERFLOW/NOOVERFLOW ......................... 11-4 The EXPORTS List .............................................. 13-4
OYfIMIZE ............................................................ 11-4 Placement of Controls .................................... ....... 13-6
OYfIMIZE(O) ............................................... 11-5
OYfIMIZE(I) ............................................... 11-5 CHAPTER 14
OP'fIMIZE(2) ............................................... 11-6 ERROR MESSAGES
OP'fIMIZE(3) ............................................... 11-8 Source PL/M-86 Errors ............................................ 14-1
OBJECT/NOOBJECT ......................................... 11-16 Fatal Command Tail and Control Errors ................. 14-20
Object Module Sections ................................ 11-16 Fatal Input/Output Errors ........................................ 14-20
DEBUG /NODEBUG ...................................... ~.... 11-17 Fatal Insufficient Memory Errors ............................ 14-20
TYPE/NOTYPE ................................................... 11-18 Fatal Compiler Failure Errors .................................. 14-20
Program Size Controls ... ..... ..... ........ ........ ... ... ....... 11-18
The SMALL Case ......................................... 11-18 APPENDIX A
TheCOMPACTCase ................................... 11-20 PLfM-86 RESERVED WORDS AND
The MEDIUM Case ...................................... 11-21 PREDECLARED IDENTIFIERS
The LARGE Case ......................................... 11-22
RAM/ROM Control..................................... 11-23 APPENDIXB
Listing Selection and Content Controls .. ... .... .......... 11-24 PROGRAM CONSTRAINTS
PRINT/NOPRINT ................................. ~ ............ 11-24
LIST/NOLIST ..................................................... 11-24 APPENDIXC
CODE/NOCODE ................................................. 11-25 GRAMMAR OF THE PLfM-86 LANGUAGE
XREF/NOXREF' .................................................. 11-25
SYMBOLS/NO~YMBOLS ................................ 11-25 APPENDIXD
Listing Format Controls ............................................ 11-26 SUMMARY OF DIFFERENCES
PAGING/NOPAGING ....................................... 11-26 BETWEEN PLfM-80 AND PLfM-86
PAGELENGTH .................................................... 11-26
PAGEWIDTH ....................................................... 11-26 APPENDIXE
TITLE .................................................................... 11-27 ASCII CODES
SUBTITLE ............................................................ 11-27
EJECT ................................................................... 11-27 APPENDIXF
Sample Program Listing ....................................... 11-28 LINKING TO MODULES WRITTEN IN
Symbol and Cross-Reference Listing ................... 11-28 OTHER LANGUAGES
Compilation Summary .......................................... 11-31
Source Inclusion Controls. ......................................... 11-32 APPENDIXG
INCLUDE ............................................................. 11-32 RUN-TIME INTERRUPT PROCESSING
SAVE/RESTORE ................................................ 11-32
Conditional Compilation Controls ............................ 11-33 APPENDIXH
IF/ELSE/ELSEIF/ENDIF ................................. 11-33 COMPILER INVOCATION AND
SET/RESET ......................................................... 11-35 ADDmONAL INFORMATION
COND/NOCOND ............................................... 11-36 FOR SERIES III USERS
APPENDIX I
COMPILER INVOCATION AND
CHAPTER 12 ADDITIONAL INFORMATION
SAMPLE PROGRAM FOR iRMX 86 USERS
xi
TABLES
ILLUSTRATIONS I
FIGURE TITLE PAGE FIGURE TITLE PAGE
l-la Sample Program: Module Sort 11-4 Sample Program Showing the
(module 1 of 2) ...................................... 1-7 OPTIMIZE(3) Control......................... 11-14
1-1 b Sample Program: Module Sort 11-5 Program Listing ........................................ 11-29
(module 2 of 2) .................................. .... 1-8 11-6 Cross-Reference Listing ............................ 11-30
3-1 Successive Byte References of a 11-7 Compilation Summary .............................. 11-31
Structure .... .... .... .... ........... ................. .... 3-18 11-8 Sample Program Showing the
7-1 Inclusive Extent of Blocks ........................ 7-2 SET(DEBUG=) Control..................... 11-34
7-2 Outer Level of Block SORT ..................... 7-3 11-9 Sample Program Showing the NOCOND
7-3 Sample Program Modules Illustrating Control................................................... 11-36
Valid GOTO Usage .............................. 7-7 12-1 Sample Program: Record Sort ................. 12-2
7-4 Valid GOTO Transfers ............................. 7-9 F-l Stack Layout at Point Where a
10-1 The iAPX 86 Hardware Flags Non-Interrupt Procedure is
Register ..... ..... .... .... ....... ......................... 10-4 Activated ............................................... F-2
10-2 The REAL Error Byte .............................. 10-7 F-2 Stack Layout During Execution of a
10-3 The REAL Mode Word ............................ 10-7 Non-Interrupt Procedure Body............. F-3
11-1 Sample Program Showing the G-l Stack Layout at Point Where an
OPTIMIZE(O) Control......................... 11-9 Interrupt Procedure Gains Control...... G-2
11-2 Sample Program Showing the G-2 Stack Layout During Execution of
OPTIMIZE(l) Control............. ............ 11-11 Interrupt Procedure Body..................... G-3
11-3 Sample Program Showing the G-3 Memory Layout of Real Save Area ......... G-IO
OPTIMIZE(2) Control......................... 11-13
xii
CHAPTER 11
INTRODUCTION
This chapter introduces the PL/M-86 language and explains the process of develop-
ing software for your iAPX 86 application system using PL/M-86.
1. 1 Product Definition
PL/M is a high-level language for programming various families of microprocessors.
It was designed by Intel Corporation to meet the software requirements of computers
in a wide variety of systems and applications work.
The PL/M-86 compiler is a software tool that translates your PL/M-86 source
programs into relocatable iAPX 86 object modules. You can then link these to other
modules coded in PL/M, assembly, or other high-level languages. The compiler
provides a listing output, error messages, and a number of compiler controls to aid in
program development and debugging. The compiler runs on an Intel microcomputer
development system.
To perform the steps following compilation, use the iAPX 86-based software devel-
opment utilities - LINK86, LIB86, CREF86, LOC 86, and OH 86. Debug your
programs using an applications debugger and the ICE-86 or ICE-88 (In-Circuit
Emulator). For firmware systems, you then use the Universal Prom Programmer
(UPP) with its Universal Prom Mapper (UPM) software to transfer your programs
to PROM.
High-level languages more closely model the human thought process than lower-level
languages such as assembly language. They therefore are easier and faster to write,
since one fewer translation step is required from concept to code. High-level language
programs are also more likely to be correct, since there is less occasion to introduce
error.
Programs in a high-level language are easier to read and understand, and thus easier
to modify. As a result, you can develop high-level language programs in a much
shorter period of time-programs that are easier to maintain throughout the life of
the product. Thus, high-level languages result in lower costs for both developing and
maintaining programs.
In addition, programs in a high-level language are easily transferred from one proces-
sor to another. Programs that can be transferred between processors without modifi-
cation are said to be portable.
If PL/M-86 is your first high-level language, you probably want to know how
programming in a high-level language differs from assembly language programming.
When you use a high-level language:
• You need not know the instruction set of the processor you are using.
• You need not be concerned with the details of the target processor, such as n~gis
ter allocation or assigning the proper number of bytes for each data item-the
compiler takes care of these things automatically.
1-1
Introduction PLfM-86 User's Guide
• You use keywords and phrases that are closer to natural English.
• You can combine many operations (including arithmetic and Boolean opera-
tions) into expressions; thus, you can perform a whole sequence of operations
with one statement.
• You can use data types and data structures that are closer to your actual problem.
For instance, in PL/M-86 you can program in terms of Boolean expressions,
characters, and data structures, in addition to bytes and words.
The introductory example at the end of this chapter (section 1.6) illustrates these
points. Compare this PL/M program with an assembly-language program you might
write to solve the same problem.
Why PL/M?
Many high-level programming languages are available today. Some of them have
been around far longer than PL/M. So, once you have decided to use a high-level
language, you might ask: How does PL/M differ from other high-level languages?
What advantages does it have? When is it the right language to use?
PL/M was designed for programmers (generally systems programmers) who need
access to the microprocessor's features-features such as indirect addressing and direct
I/O for optimum use of all system resources.
What about the differences between PL/M and older, more established languages
like FORTRAN, BASIC, and COBOL? PL/M has many more features than BASIC
and is a more general-purpose language than either FORTRAN (best suited for
scientific applications) or COBOL (tailored for business data processing). Addition-
ally, PL/M differs from these other languages in its typing and block structure.
1-2
PL/M-86 User's Gtdde IntroduetioD
A module is a labeled simple DO-block; that is, a module must begin with a labeled
DO statement and end with an END statement. Between those end points (i.e., within
that DO-block), other statements provide the definitions of data and processes that
make up the program. These statements are said to be part of the block, contained
within the block, or nested within the block. A module can contain other blocks but
is never itself contained within another block.
(The reason for saying usimple" DO-block is that DO-blocks are of three other
varieties, which are explained in Chapter 6.)
NOTE
The word EOF in PL/M-86 is a reserved word indicating the end of the file.
It should not be used as an identifier because the remainder of the module it
is used in will be ignored at compile-time.
Every PL/M-86 program consistg of one or more modules, separately compiled, each
consisting of one or more blocks. There are two kinds of blocks: DO-blocks and
procedure definiton blocks.
There are two types of statements in PL/M-86: declarations and executable state-
ments.
Declaration Statements
A simple example of a declare statement is:
1-3
Introduction PLfM-86 User's Guide
Executable Statements
CLEARANCE = WIDTH + 2;
Here, we have two identifiers, CLEARANCE and WIDTH. Both must be declared
prior to this executable statement, which produces machine code to retrieve the
WIDTH value from memory. Once you obtain the WIDTH value, add 2 to it and
store the sum 'in the memory location for CLEARANCE.
For most purposes, the PL/M-86 programmer need not think in terms of memory
locations. CLEARANCE and WIDTH are variables, and the assignment statement
assigns the value of the expression WIDTH + 2 to the variable' CLEARANCE. The
compiler automatically generates all the machine code necessary to retrieve data from
memory, to evaluate the expression retrieved, and to store the result in the proper
location.
The following is a list of all PL/M-86 executable statements and the chapters in
which they are fully discussed:
Expressions
Operands include numeric constants (such as 3.78 or 105) and variables (as well as
other types discussed in Chapters 3 and 4). The operators include + and - for
addition and subtraction, * and / for multiplication and division, and MOD for modulo
arithmetic.
1-4
PL/M-86 User's Guide Introduction
PL/M-86 does not provide formatted I/O capabilities like those of FORTRAN,
BASIC, or COBOL. PL/M-86 does provide built-in functions for direct I/O which
do not require operating system run-time support. For single-byte or single-word
I/O, these functions are INPUT, INWORD, OUTPUT, and OUTWORD. For block
I/0, they are BLOCKINPUT, BLOCKINWORD, BLOCKOUTPUT, and
BLOCKOUTWORD.
INPUT causes the program to read the 8-bit quantity found in one of the 64K input
ports of the iAPX 86. A reference to OUTPUT causes the program to place an
8-bit quantity into one of the 64K output ports of the iAPX 86.
INWORD and OUTWORD have the same effects as INPUT and OUTPUT except
that they handle 16-bit (WORD) quantities instead of 8-bit (BYTE) quantities.
BLOCKINPUT causes the program to read a string of 8-bit quantities found in one
of the iAPX 86 input ports. BLOCKOUTPUT places a string of 8-bit quantites into
one of the iAPX 86 output ports.
The PL/M-86 compiler is part of an integrated set of tools that make up the total
iAPX 86 development solution for your microcomputer system.
1-5
Introduction PL/M-86 User's Gaide
Figure 1-1 shows the listing of a sample PL/M-86 program divided into two modules.
This program contains many undefined words and constructs that will be explained
in the upcoming chapters. The programs appear here: 1) to show what a small
PL/M-86 program looks like separated into two modules, and 2) to explain, step by
step, how to compile, link, and run programs on your development system.
The interactive computer dialogue in this section consists of commands you enter,
which are immediately echoed on the console display, and text displayed by the
operating system, the PL/M-86 compiler, and other Intel-supplied programs. The
text you enter is shown in reverse type (white on a black background), and the text
displayed by Intel programs is shown in normal black type. The notation <cr) stands
for the RETURN key on the console keyboard. Note that the operating system prompt
(indicating that it is ready to accept a command) and, for some systems, the name of
the loader (e.g., RUN on the Series III) are not included. See the appendix for your
specific operating system for details.
The main program, to be compiled as a module named "M," does little but define
some data and then call the procedure named SORTPROC. This procedure is dermed
in the other module, which is to be compiled with the name SORTMODULE. To
prepare this sample program for execution, first type it in using a text editor.
Then, compile each module separately. For example, if the file PROGIA.SRC
contains the module SORTPROC, then you would invoke the compiler with the
command:
This process would then be repeated with the file PROGIB.SRC, which contains the
module M.
Next, link the resulting object modules using the LINK86 command
1-6
PLfM-86 User's Guide Introduction
: : = ~, ( = r >
/* Parameters:
PTR is pointer to first record
COUNT is nwnber of records to be sorted.
RECSIZE is number of bytes in each record - maximum
is 128.
KEYINDEX is byte position within each record of a
BYTE scalar
to be used as sort key.*/
4 2 DECLARE RECORD BASED PTR(I) BYTE,
CURRENT(128) BYTE,
(I,J) WORD;
5 2 SORT: DO J = 1 TO COUNT-I;
6 3 CALL MOVB(@RECORD(J*RECSIZE),@CURRENT, RECSIZE);
7 3 I=J;
8 3 FIND: DO WHILE 1>0 AND
RECORD«I-l)*RECSIZE + KEYINDEX»
CURRENT(KEYINDEX);
9 4 CALL MOVB(@RECORO«I-l)*RECSIZE),
@RECORD(I*RECSIZE), RECSIZE)i
HI 4 1=1+1;
11 4 END FIND;
12 3 CALL MOVB(~CURRENT, @RECORD(I*RECSIZE), RECSIZE)i
13 3 END SORT;
14 2 END SORTPROCi
15 1 END SOR'rMODULE; /*End of Module* /
MODULE INFORMATION:
1-7
Introduction PL/M-86 User's Guide
MODULE INFORMATION:
1-8
CHAPTER 2
LANGUAGE ELEMENTS
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789
and the blank or space; plus the tab, carriage-return, and line-feed characters.
The rules in this section apply to everything in a PLfM-86 program except character
string constants (section 2.4), and comments (section 2.5).
If a PL/M-86 program contains any character that is not in the set above, the compi-
ler treats it as an error (or, in some cases, a warning only; see Chapter 14).
Uppercase and lowercase letters are not distinguished from each other except in string
constants. For example, xyz and XYZ are interchangeable. In this manual, all
PL/M-86 code is in uppercase letters to help distinguish it from explanatory text.
Blanks are not distinguished from each other except in string constants. The compiler
treats any unbroken sequence of blanks as a single blank.
2-1
Laagage Elements PL/M-86 User's GuitIe
For the most part, it is obvious where one token ends and the next one begins. For
example, in the assignment statement:
EXACT-APPROX*(OrrSET-3)/SCALE;
EXACT, APPROX, OFFSET, and SCALE are identifiers, 3 is a numeric constant,
and all the other characters are simple delimiters.
Sometimes a simple or compound delimiter does not occur between two identifiers,
reserved words, or numeric const~nts--e.g., DECLAREABYTE. In these cases, a
blank must be placed between them as a separator. (Instead of a single blank, any
unbroken sequence of blank characters may be used.)
2-2
PL/M-86 User's Guide Language Elements
Blanks may be inserted freely around any token without changing the meaning of the
PL/M-286 statement. Thus~ the assignment statement:
EXACT - APPRDX • ( OFFSET - 3 ) / SCALE;
is equivalent to:
EXACT-APPRDX*(DFFSET-3)/SCAlE;
Embedded dollar signs are totally ignored by the compiler, and may be used freely
to improve the readability of an identifier or constant (although the $ may not be the
first character). An identifier or constant containing a dollar sign is exactly equiva-
lent to the same identifier with the dollar sign deleted.
The long identifiers are identical (to the compiler). The last two examples are inter-
changeable, but are different from the first.
Certain reserved words must not be used as identifiers because they are actually part
of the PL/M-86 language. These are listed in Appendix A.
There is also a set of predeclared identifiers naming built-in procedures and variables.
You are permitted to declare these names for your own purposes, but when you do
so the built-in value or procedure becomes inaccessible. Appendix A lists these
identifiers.
2.4 Constants
A constant is a value that does not change during your program's execution. There
are three types of constants: whole-number constants, floating-point constants, and
character strings.
Whole-Number Constants
Whole-number constants can be binary, octal, decimal, or hexadecimal. The compiler
recognizes these by a suffix of B, 0 (or Q), D, 'or H. Numbers without a suffix are
considered decimal. If a constant contains characters invalid in the designated number
base, it will be flagged as an error.
2-3
Language Elements PLfM-86 User's Guide
The first character of a hexadecimal number must be a numeric digit to avoid looking
like an identifier. For example, the hexadecimal representation for 163 must be written
OA3H rather than A3H, which would be taken as an identifier.
12AD Here the final D could be a suffix but the A is not a decimal digit.
If hexadecimal is intended, a final H is needed.
l1A2B 'A' and '2' are not valid binary digits. If hexadecimal is intended,
a final H is necessary.
Note that a minus sign in front of a constant is not part of the constant. An INTEGER
value may be negative, but the range of whole-number constants is non-negative.
Floating-Point Constants
At least one decimal digit (e.g., 0) must precede the decimal point. A fractional part
is optional after the decimal point, as is the base-ten exponent, which is indicated by
the letter E. This exponent must have at least one digit. Note that no fractional
exponents are possible. The largest REAL constant value is 3.37 X 10+ 38, and the
smallest REAL is 1.17 X 10-38 •
The exponents in the third and sixth examples are the same; plus signs don't change
the meaning.
6 No decimal point
1.3AH Hexadecimal not allowed in REALs
10.OlIB Binary not allowed in REALs
7.52Q Octal not allowed in REALs
4.8EIAHJ2 Only decimal constants in exponents-no hexadecimal, no
expressions, no fractions
2-4
PL/M-86 User's Guide Language Elements
Character Strings
'A' is equivalent to 41 H
'AG' is equivalent to 4147H
'AGR' is equivalent to 414752H
'AGRX' is equivalent to 41475258H
Therefore, character strings can be used only as BYTE, WORD, or DWORD values
since strings longer than 4 characters would exceed the 32-bit capacity of a DWORD
value. As constants, however, longer character strings are stored as a sequence of
bytes and can be used in a PLfM-86 program (see Chapter 3).
The maximum length of a string constant is 255 characters. It can be used only as
an initialization for an array or as part of a location reference pointing to where that
string constant is stored.
2.5 Comments
Explanatory comments may be interleaved with PLfM-86 program text to improve
readability and provide program documention. A PLfM-86 comment is a sequence
of characters delimited on the left by the character pair j* and on the right by the
character pair * f. These delimiters instruct the compiler to ignore any text between
them and to consider such text not a part of the program proper.
A comment may contain any printable ASCII character and may also include space,
carriage-return, line-feed, and tab characters.
A comment may not be embedded inside a character string Constant, i.e., it will become
part of the string and the compiler won't recognize it. Apart from this, it may appear
anywhere that a blank character may appear-that is, anywhere except embedded
within a token. Thus, comments may be freely distributed throughout a PLfM-86
program.
In this manual, comments are presented in uppercase and lowercase to help distin-
guish them visually from program code, which is always presented in uppercase.
2-5
CHAPTER 3
DATA DECLARATIONS, TYPES,
AND BASED VARIABLES
Four types of objects can be declared to have symbolic names: variables, constants,
labels, and procedures. One declaration must be available for each name used in a
block-no more, no less. This declaration may appear at the beginning of the block,
or in an enclosing outer block. Multiple declarations of the same name in the same
block are invalid.
Only after being declared and defined can names for the four elements above be used
in executable statements. For variables, constants, and labels, such usage is, in essence,
an operational definition. For a procedure, the set of statements between its declara-
tion and its end statement constitutes its definition.
In addition to the item's name, a declaration tells its type, attributes, and/or location.
These terms will be clarified in the course of this chapter.
Table 3-1 shows the general appearance of declarations, e.g., required or optional
elements.
A scalar variable is a single object whose value is not necessarily known at compile
time and may change during the execution of the program. You therefore refer to it
by declaring a name to be used in the program. This name is known as an identifier.
3-1
Data Declarations, Types, aDd Based Variables PLJM-86 User's Guide
An array is a list of scalars all named by the same identifier, differentiated from each
other by the use of subscripts, e.g., A( 0), a( I ), A( 123), and so on.
A structure is a list of scalars and/or arrays that all use the same main identifier and
that can be differentiated from each other by their own member-identifiers (field
names). For example, EMPLOYEES. NAME could refer to the NAME field within
the structure EMPLOYEES. .
Such variables (arrays and structures) are discussed in greater detail in Chapter 5.
Examples
The third example declares two scalars of different types: POINT is of type WORD,
and VAL 12 is of type BYTE.
The second statment declares the array GAMMA, with 19 scalar elements of type
DWORD. The subscripts for this array can range from 0 to 18.
Further discussion of structures appears in sections 3.4 and 3.6, and. in Chapter 5.
3-2
PL/M-86 User's Guide Data Declarations, Types, and Based Variables
Results
The two results of a valid variable declaration are:
1. The name is given a unique address.
2. The variable is considered to have the attributes declared.
This means that all subsequent uses of the variable in the block where it is declared
will refer to the same address (except for based variables, discussed in section 3.5).
A valid variable declaration also requires all references to the variable to conform to
the rules for the current attributes, i.e., those having priority in the current block.
Thus, the compiler can flag a large variety of errors that are caused by incompatible
declarations within the current block.
Previously, most examples have shown only one declaration element in each
DECLARE statement. A declaration element is the text for declaring one identifier
(or one factored list of identifiers). In the example above, the text
CHR BYTE INITIAL ('A') is one declaration element, and the text
COUNT INTEGER is another.
Variables declared in a "factored" declaration that are not based, and not used as
parameters-that is, variables within a parenthesized list-are stored contiguously in
the order specified. (If a based variable occurs in a parenthesized list, it is ignored
when storage is allocated.)
3-3
Data Declarations, Types, and Based Variables PL/M-86 User's Guide
3.2 Initializations
Initialization is necessary for every constant and variable name that is used (read)
before it is filled (written) during execution since there are no default values. Either
kind of name can, of course, be initialized by an assignment statement such as:
PI = 3.1415927; /' PI must first be declared REAL. '/
VAR13 = 10; /' VAR13 must be declared earlier, not real. 1/
However, the PL/M-86 language provides a means for having the compiler set up
these values during the compilation rather than using both instruction space and
execution time in your program to do so.
There are two kinds of compile-time initializations: INITIAL, used with variables,
and DATA, used for constants. (DATA is explained in greater detail later in this
section.) In each case, the initialization attribute is placed after the type in the
declaration. For example:
DECLARE FAMILY WORD INITIAL (2);
INITIAL causes initialization to occur during program loading for variables that
have storage allocated for them. Such variables can subsequently be changed during
execution, like any other variable. (They will not be reinitialized on a program restart.)
I NIT I AL (value-list)
where
value-list is a sequence of values separated by commas.
Values are taken one at a time from the value list and used to initialize the individual
scalars being declared. The initialization is performed in the same manner as an
assignment. Initial values for members of an array or structure must be specified
explicitly. (See also section 9.4 for built-in procedures you can use to initialize BYTE
and WORD strings at run-time.)
3-4
PL/M-86 User's Guide Data Declarations, TYIk->S, and Based Variables
NOTE
For compatibility with programs written in PLjM-80, PLjM-86 allows the
restricted expression to be an expression containing a location reference
formed with the '~dot" operator.
The declaration:
The declaration:
The declaration:
COORD.HIGH$BOUND to 302
COORD.VALUE(O) to 3
COORD.VALUE(1) to 6
COORD.VALUE(2) to 12
COORD.LOW$BOUND to o
If a string appears in the value list, it is taken apart from left to right and the pieces
are stored in the scalars being initialized. One character is stored in each BYTE
scalar, two in each WORD scalar, and four in each DWORD scalar. For example:
So far, all the examples have shown value lists that match up one-for-one with the
scalars being declared. It is permissible for the value list to have fewer elements than
are being declared. Thus:
3-5
Data Declaratio~ Types, and Based Variables PL/M-86 User's Guide
This may also be used to define an external array whose precise number of elements
is either unknown or insignificant. Thus the declaration:
The implicit dimension specifier may not be used in the following cases:
• After the parenthesized list of identifiers in a factored declaration.
• To specify an array whose elements are structures.
• To specify an array that is a member of a structure.
The implicit dimension specifier may be used with any value list-it is not restricted
to strings.
For example, the formula for the circumference of a circle as the product of its radius
and two pi could be written in PL/M-86 as:
C • R • 2.0 I 3,14159;
in which C and R would be variables. Their declarations would of course have to
precede the above executable statement, and could appear as:
3-6
PL/M-86 User's Guide Data Declarations,Types, and Based Variables
If your program were large enough to have many declarations, you might choose to
declare a compilation constant to save time at the keyboard:
DC AREA REAL;
DC SIZE WORD;
A declaration using the reserved word LITERALLY defines a parameterless "macro"
for expansion at compile-time. You declare an identifier to represent a character string,
which will then be substituted for each occurrence of the identifier in subsequent text.
This expansion will not take place in strings or constants. The form of the
declaration is:
where
identifier is any valid PL/M-86 identifier.
string is a sequence of arbitrary characters from the PL/M-86 set,
not exceeding 255 in length.
3-7
Data Declarations, Types, and Based Variables PL/M-86 User's Guide
ROUGH • TRUE;
DO WHILE ROUGH;
X • SMOOTH ex, Y, DELTA);
/* SMOOTH is a procedure declared elsewhere. */
IF eX-FINAL) ( DELTA THEN ROUGH = FALSE;
END;
This example of a LITERALLY declaration defines the boolean values TRUE and
FALSE in a manner consistent with the way PL/M-86 handles relational operators
(see section 4.3). This kind of literal substitution for fixed values often makes a
program more readable.
Another use of the LITERALLY declaration is the declaration of quantities that are
fixed for one compilation, but are subject to change from one compilation to the next.
Consider the example below:
A future change to BUFFER$SIZE can be made in one place, at the first declara-
tion, and the compiler will propagate it throughout the program during compilation.
Thus, the programmer is saved the tedious and error-prone process of searching the
program for the occurrences of ~'32" that are buffersize references and not 32's that
are used in other contexts.
A label marks the location of an instruction as opposed to a data item. Labels are
permitted only on executable statements, not on declarations.
There are two ways to declare a name as a label. Explicit label declarations are used
mainly to allow for module-to-module references, which are discussed in detail in
Chapter 9. The three possible forms for explicit label declarations look like this:
The more common label declaration, implicit, is even simpler: the name is placed at
the very beginning of the executable statement it is supposed to point to. For example:
3-8
PL/M-86 User's Guide Data Declarations, Types, and Based Variables
This statement defines the label START2 as pointing to the location of the
PL/M-86 instruction shown. If this block has no explicit declaration of START2,
i.e., no statement like:
Labels are used to indicate significant instructions or the starting point of instruction
sequences. Labels can be useful reference points for understanding the parts of a
program, or targets for the transfer of control during execution (as discussed under
GOTO and CALL in Chapters 7 and 8).
Results
The results of a valid label declaration are:
l. The declared name can be used to point to an executable instruction.
2. The use of the declared name as a variable in its block is disallowed.
3. If the label is also defined in its block by appearing in an executable statement,
then the address of that statement is assigned as the value of the label.
As illustrated earlier, the declaration of a procedure begins by giving its name, with
a statement of the form:
name: PROCEDURE
followed optionally by parameters, type and/or attributes. The definition of the
procedure then follows, i.e., the set of statements declaring items used in the proce-
dure (including any parameters) and the executable statements of the procedure itself.
The definition ends with an END statement, optionally including the procedure name
from the declaration.
The complete declaration of a procedure includes all the statements from the
PROCEDURE statements through the END statement. This whole
definition/declaration must appear before the procedure name is used in an execut-
able statement, just as variable and constant names must be declared before their
use.
The only exceptions arise when the full definition appears in another module where
it is declared PUBLIC, or when a procedure has been declared REENTRANT. In
the first case, if a separate module intends to make use of that public definition, it is
required to:
1. Decla the procedure a aving the EXTERNAL attribute (so the Linker will
se h for it).
2. eclare each formal parameter he procedure uses so the compiler can verify
~_____________/,,/ correct usage when this module in okes the procedure.
3-9
Data Declarations, Types, and Based Variables PL/M-86 User's Guide
For example:
Arithmetic and other expressions using the different types are discussed in detail in
Chapter 4.
The value of a BYTE variable is an 8-bit binary number ranging from 0 to 255 and
occupying one byte of iAPX 86 memory (two bytes when passed as a parameter on
the stack, see Appendix F). The value of a WORD variable is a 16-bit binary number
ranging from 0 to 65535 and occupying two contiguous bytes of iAPX 86 memory
(the least significant 8 bits are stored in the lower address). The value of a DWORD
variable is a 32-bit binary number ranging from 0 to 4,294,967,295 and occupying
two contiguous words of iAPX 86 memory (the least significant 16 bits are stored in
the lower address). Values of DWORD, WORD, and BYTE variables are treated as
unsigned binary integers.
NOTE
Support for *, /, and MOD operations on DWORD is located in the
PLM86.LIB support library. You must link to this library before executing
any program that performs these operations on DWORD types. (The
DWORD routines in this library form only one segment: a code segment
called LQYLM86_LIB_CODE. Since this is read-only code, it may be
burned into ROM.)
With unsigned arithmetic, if a large value is subtracted from a smaller one, the result
is the two's complement of the absolute difference between the two values. For
example, if a BYTE value of 1 (00000001 binary) is subtracted from a BYTE value
of 0 (00000000 binary), the result is a BYTE value of 255 (11111111 binary).
Also, the result of a division operation is always truncated (rounded down) to a whole
number. For example, if a WORD value of 7 (0000000000000111 binary) is divided
by a BYTE value of 2 (00000010 binary), the result is a WORD value of 3
(00000000000000 11 binary).
3-10
PL/M-86 User's Guide Data Declarations, Types, and Based Variables
When declaring a variable that may be used to hold or produce a negative result, it
is advisable to make it either INTEGER or REAL. If it is supposed to hold or produce
a non-integer, it must be REAL. Making use of the appropriate data types can help
avoid unexpected incorrect results from arithmetic operations (see Chapter 4).
MAGNITUDE
15 14 o
The sign bit is 0 if the INTEGER value is positive or zero, and I if the value is
negative. The magnitude is given in two's complement notation.
However, as with BYTE, WORD, and DWORD operands, division produces only an
INTEGER result. The result is rounded toward zero, i.e., down if it is positive, up if
it is negative.
Only the arithmetic and relational operators may be used with INTEGER operands.
Logical operators are not allowed (see Chapter 4).
The value of a REAL variable is a signed floating-point number that occupies four
contiguous bytes of iAPX 86 memory, which may be viewed as 32 contiguous bits in
the short-real format. The bits are divided into fields as follows:
I I
31
SIGN
30
EXPONENT I
23 22
S1GNIFICAND
The byte with the lowest address contains the least significant 8 bits of the
significand, and the byte with the highest address contains the sign bit and the most
significant 7 bits of the exponent field.
The sign bit is 0 if the REAL value is positive or zero, and I if the REAL value is
negative.
The exponent field contains a value "offset" by 127-in other words, the actual
exponent can be obtained from the exponent field value by subtracting 127. This field
is all O's if the REAL value is zero.
The significand contains the binary digits of the fractional part of the REAL value
when this part is represented in "binary scientific" notation (see below). This field is
all 0' s if the REAL value is zero.
3-11
Data Declarations, Types, and Based Variables PL/M~ User~s Guide
The utility of the REAL data type is extended by the PL/M-86 compiler's practice
of holding intermediate results in the 8087's temporary-real format. This format
preserves 64 bits of precision and the full range of representable numbers. The
exponent in this format is 15 bits instead of 8 in the short-real format.
This greater range of exponent greatly reduces the likelihood of underflow and
overflow, and eliminates roundoff as a source of error until the final assignment of
the result is performed. These advantages arise because" underflow, overflow, and
roundoff errors are more probable for intermediate computations than for the final
result. For example, an intermediate underflow result might later be multiplied by a
very large factor, providing a final result of acceptable magnitude.
3-12
PL/M-86 User's Guide Data Declarations, Ty~ and Based Variables
The largest possible value for a valid exponent field is 254, which corresponds to
an actual exponent of 127. The largest possible absolute value for a positive or
negative REAL value is therefore
1.1111111111111111111111IB * 2127
or approximately 3.37 * 1038•
The lowest permissible exponent field value for a non-zero REAL value is I,
which corresponds to an actual exponent of -126. The smallest possible absolute
value for a positive or negative REAL value is therefore
1.0B * 2- 126
or approximately 1.17 * 10-38 •
SELECTOR OFFSET
31 1615 o
Among other uses, POINTER variables are important as bases for based variables
(see section 3.5).
Only the relational operators may be used with POINTER operands, yielding a ~~true"
or "false" result of type BYTE. No arithm", ..ic or logical operations are allowed (see
Chapter 4).
There are only a few ways to create or change the value of a POINTER variable,
that is, the address that the variable points to:
I. The variable can be initialized when declared, using INITIAL or DATA with an
address created with a whole-number constant as described in section 3.2.
2. The variable can be assigned a whole-number constant as described in
Chapter 4.
3. The variable can be assigned an address created via the @ operator (described
below). This is the safest and most commonly used method.
4. The variable can be assigned the value of a POINTER variable or function.
5. The variable can be assigned a value generated by the BUILD$PTR or NIL
functions (described in section 9.6).
.
The @ Operator
A '~location reference" is formed by using the @ operator. A location reference has a
value of type POINTER-that is, a location address. An important use of location
references is to suPI'IY values for POINTER variables.
• variable-ref
where
variable-ref is the name of some variable.
The value of this location reference is the actual run-time location of the variable.
3-13
Data Declarations, Types, and Based Variables PL/M·86 User's Guide
The variable.refmay also refer to an unqualified array or structure name. The pointer
value is the location of the first element or member of the array or structure.
The RECORD structure declares a byte called KEY followed by 25 bytes called
INFO(O), INFO(l), and so on, followed by the POINTER variable named HEAD.
Since KEY, INFO, and. HEAD are all declared part of the RECORD structure,
their contents must be referred to as RECORD. KEY, RECORD.lNFO(O),
... , RECORD.INFO(24), and RECORD.HEAD.
The addresses of these elements of the RECORD structure can be referred to using
the @ operator. @RECORD.HEAD is the location of the POINTER scalar
RECORD. HEAD, while @RECORD is the location of the structure, which is the
same as that of the BYTE scalar RECORD. KEY. @RECORD.INFO is the location
of the first element of the 25-byte array RECORD. INFO, whereas
@RECORD.lNFO(7) is the location of the 8th element of the same array.
A special case exists when the identifier used as "variable-ref" is the name of a proce-
dure. The procedure must be declared at the outer level of the program module. No
actual parameters may be given (even if the procedure declaration includes formal
parameters). The value of the location reference in this case is the location of the
entry point of the procedure. (Further discussion of procedures appears in Chapter 8
and Appendixes F and G.)
Storing Strings and Constants via Location References. Another form of location
reference is:
• ( constant list>
where
constant list is a sequence of one or more constants separated by commas
and enclosed by parentheses.
When this type of location reference is made, space is allocated for the constants, the
constants are stored in this space (contiguously, in the order given by the list), and
the value of the location reference is the location of the first constant.
3-14
PLjM-S6 User's Guide Data DeclaratioM, Types, and Based Variables
,('NEXT VALUE')
appears in an expression, it causes the string 'NEXT VALUE' to be stored in memory
(one character per byte, thus occupying 10 contiguous bytes of storage). The value
of the operand is the location of the first of these bytes-in other words, a pointer to
the string.
SELECTOR Variables
SELECTOR
31 16
Only the relational operators may be used with SELECTOR operands, yielding a
"true" or "false" result of type BYTE. No arithmetic or logical operations are allowed
(see Chapter 4).
There are only three ways to create or change the value of a SELECTOR variable:
1. The variable can be initialized when declared, using INITIAL or DATA with a
whole-number constant as described in section 3.2.
2. It can be assigned a whole-number constant as described in Chapter 4.
3. It can be assigned a SELECTOR variable or function, or the build-in function
SELECTOR$OF (see section 9.7).
The results of the @ and dot operators may not be assigned to SELECTOR variables
directly. They must first be converted to SELECTOR type with the built-in function
SELECTOR$OF (see section 9.7).
3-15
Data Declantions, Types, and Based Variables PL/M-86 User's Guide
A based variable is not allocated storage by the compiler. At different times during
the program run it may actually refer to different places in memory, since its base
may be changed by the program.
A based variable is declared by first declaring its base, which must be of type
POINTER, SELECTOR, or WORD, and then declaring the based variable itself:
DECLARE I BYTE;
DECLARE ITEM$PTR POINTER;
DECLARE ITEM BASED ITEM$PTR BYTE;
ITEM$PTR • ,I;
ITEM • 77Hj
A variable is made BASED by inserting in its declaration the word BASED and the
identifier of the base (which must already have been declared).
The word BASED must immediately follow the name of the based variable in its
declaration, as in the following examples:
In the second DECLARE statement, a BYTE variable called AGE is declared. The
declaration implies that whenever AGE is referenced by the running program, its
value will be found at the location given by the value of the POINTER variable
AGE$PTR at the same time.
The third DECLARE statement declares two based variables, both of type WORD.
3-16
PL/M-86 User's Guide Data Declarations, Types, and Based Variables
The other elements follow contiguously. The parentheses around the tokens
CATEGORY BASED CATEGOR YSPTR are optional. They help to make the
statement more readable, but may be omitted.
ERRORSPTR • ,HEIGHTSERROR;
Now a reference to ERROR will, in effect, be a reference to HEIGHTS ERROR. In
the same way, we can cause the value of the pointer to be the location of
EASTSERROR, and a reference to ERROR will be a reference to EASTSERROR.
This technique is useful for manipulating complicated data structures and for passing
locations to procedures as parameters. Examples are given in Chapter 8.
A T ( location)
where
location must be a location reference formed with the @ operator, or
a single whole-number constant in the range 0 to 1,048,575.
It must refer to a non-based variable that has already been declared. If there is a
SUbscript expression, it must be a constant expression containing no operators except
+ and-.
The following are examples of valid AT attributes:
AT (4096)
AT (,BUFFER)
AT (,BUFFER(128»
AT (,HAMESCIHDEX + 1»
3-17
Data Declarations, Types, and Based Variables PL/M-86 User's Guide
In the last example, INDEX represents a whole-number constant that has been previ-
ously declared with a "LITERALLY" declaration. The compiler replaces this name
with the declared whole-number constant, thus satisfying the restrictions given above.
NOTE
For compatibility with programs written in PLfM-80, PLfM-86 allows the
location in an AT attribute to be an expression containing a location refer-
ence formed with the "dot" operator. (See Appendix D.)
The declaration:
The declaration above, using the AT attribute, causes the beginning of the structure
T-namely the scalar T(O).X(O)-to be located at the same location as a previously
declared variable called DATA$BUFFER. The other scalars making up the structure
will follow this location in logical order: T(O).X(l), T(0).X(2), and so on up to
T(9).Z(2), the last scalar, which is located in the 89th byte after the location of
DATA$BUFFER.
However, no memory locations for these 90 scalars are allocated by this declaration.
It is up to the programmer to know what else, if anything, will be stored in the memory
space starting at @DATA$BUFFER.
T(O).X(O)
T(O).X(1)
T(O).X(2)
T(O).Y(O)
T(O).Y(1)
T(O).Y(2)
T(O).Z(O)
T(O).Z(1)
T(O).Z(2)
T(1).X(O)
T(1).X(1)
T(1).X(2)
T(1).Y(O)
T(1).Y(1)
ANDSOON
3-18
PL/M-86'User's Guide Data Declarations, Types, and Based Variables
The AT attribute can be used to make variables "equivalent," providing more than
one way of referring to the same information. For example:
causes ITEM to be declared a BYTE variable at the same location that has just been
allocated for the WORD variable DATUM. The result is that any reference to ITEM
is, in effect, a reference to the low-order byte of DATUM (because WORD values
are stored with the low-order 8 bits preceding the high-order 8 bits).
Thus, we have two different ways of referring to the same six bytes. For example, the
fifth byte in the group can be referenced as either VECTOR( 4) or
SHORT$VECTOR.SECOND(l ).
When a variable is declared with the AT attribute, the PL/M-86 Compiler does not
optimize the machine code generated to access that variable except under
OPTIMIZE(3).
3-19
CHAPTER 4
EXPRESSIONS AND ASSIGNMENTS
A+B
A+B-C
A*B + C/D
A*(B + C) - (D - E)/F
This chapter presents a complete discussion of the rules governing PL/M-86 expres-
sions. Although these rules may appear complex, bear in mind that most of the
expressions used in actual programs are simple and easy to understand. In particular,
when the operands of arithmetic and relational operators are all of the same type,
the resulting expression is easy to understand.
4. 1 Operands
Operands are the building blocks of expressions. An operand is something with a
value at run time that can be operated upon by an operator. Thus, in the examples
above, A, B, C, etc., might be the identifiers of scalar variables which have values at
run time.
Numeric constants and fully qualified variable references may appear as operands in
expressions. The following sections describe all of the types of operands that are
permitted.
Constants
Any numeric constant may be used as an operand in an expression. Its type must be
appropriate, as discussed below.
A string constant containing not more than four characters may also be used as an
operand. If it has only one character, it is treated as a BYTE constant whose value is
the eight-bit ASCII code for the character. If it is a two-character string, it is treated
4-1
ExpressioDS and Assignments PL/M-86 User's Guide
as a WORD constant whose value is formed by stringing together the ASCII codes
for the two characters, with the code for the first character forming the most
significant eight bits of the sixteen-bit number.
Strings of more than four characters are called string constants. They are illegal. as
operands in expressions, and may appear in only two contexts: as initialization values
for an array or as part of a location reference that points to where the string constant
is stored (see Chapter 3).
A function reference is the name of a "typed procedure" that has previously been
declared, along with any parameters required by the procedure declaration. The value
of a function reference is the value returned by the procedure.
• J + ABS(L)j
the absolute value of L will be returned by the function ABS and then added to the
value of J before being stored in I. If L is - 27, the result is exactly as if you had
written:
• J + 27j
Subexpressions
A subexpression is simply an expression enclosed in parentheses. A subexpression
may be used as an operand in an expression. This is the same as saying that paren-
theses may be used to group portions of an expression together, just as in ordinary
algebraic notation.
Compound Operands
All the operand types described above are primary operands. An operand may also
be a value calculated by evaluating some portion of the total expression. For example,
in the expression
4-2
PLJM-86 User's Guide Expressions and Assignments
A + B*C
(where A, B, and C are variable references), the operands of the * operator are B
and C .. The operands of the + operator are A and the compound operand B * C-or
more precisely, the value obtained by evaluating B * C. Notice that this expression
is evaluated as if it had been written
A + (B * C)
This analysis of an expression to determine which operands belong to which
operators, and which groups of operators and operands form compound operands, is
discussed in section 4.5.
+-* / MOD
All of these operators are used as in ordinary algebra to combine two operands. Each
operand may have a BYTE, WORD, DWORD, INTEGER, or REAL value (except
that REAL operands are not allowed with the MOD operator). Arithmetic
operations on POINTER and SELECTOR variables are not allowed.
The operators +, - ,*, and / perform addition, subtraction, multiplication, and division
on operands of any type except POINTER and SELECTOR. The following rules
govern these operations (see also table 4-2).
1. If both operands are of the same type, the result is of the same type as the
operands, with only one exception: if both operands are of type BYTE, the * and
/ operations produce results of type WORD. The type of arithmetic depends on
the type of operands, as discussed in Chapter 3.
2. Only three combinations of mixed operand types are allowed. A BYTE operand
can be combined with a WORD operand, a BYTE operand can be combined
with a DWORD operand, and a WORD operand can be combined with a
DWORD operand. In the first two cases, the BYTE operand is extended by 8
high-order zero bits to produce a WORD value, or by 24 high-order zero bits to
produce a DWORD value. Similarly, a WORD operand is extended by 16 high-
order zero bits to produce a DWORD value. Then the operation is performed as
though both operands are of the same type.
3. If one operand is a whole-number constant, and the other is a DWORD, WORD,
or BYTE operand, the whole-number constant is treated as a BYTE value. if it
is equal to or less than 255, a WORD value if it is greater than 255 and equal to
or less than 65,535, and a DWORD value if it is greater than 65,535. Then the
operation is performed under rule I or rule 2 above. If the whole-number constant
exceeds 4,294,967,295, the operation is invalid.
4. If one operand is a whole-number constant and the other is an INTEGER
operand, the whole-number constant is treated as a positive integer value. Then
the operation is performed as if both operands were INTEGER operands. If the
whole-nurrtber constant exceeds 32,767, the operation is invalid.
5. If one operand is a whole-number constant and the other is of type REAL,
POINTER, or SELECTOR, the operation is invalid.
4-3
Expressions and Assignments PLfM-86 User's Guide
Its effect is that (- A) is equivalent to (0- A), where A is any operand. The 0 is a
BYTE value if A is of type BYTE, WORD, or DWORD, an INTEGER value if A
is of type INTEGER, or a REAL value if A is of type REAL. If A is a whole-number
constant, its type and the unary "-" operation depend on the context as explained
in section 4.6.
Finally, a unary "+" operator is defined for the sake of completeness. As in ordinary
algebra, a unary" +" has no effect, and ( + A) is exactly equivalent to (A).
For example, if A and B are INTEGER variables with values of 35 and 16, respec-
tively, then A MOD B yields an INTEGER result of 3, and - A MOD B yields - 3.
Unlike the / operator, the MOD operator must be separated from surrounding letters
and digits by blanks or other separators.
Relational operators are always binary operators, taking two operands, to yield a
BYTE result, as follows:
If both operands are of the same type, unsigned arithmetic is used to compare two
BYTE values, two WORD values, or two DWORD values; signed arithmetic is used
to compare two INTEGER values or two REAL values; and POINTER or
SELECTOR values are compared for equality or inequality according to the ordering
of iAPX 86 locations.
4-4
PLfM-86 User's Guide Expressions and Assignments
NOTE
If segments are overlapped in your program and you compare POINTER or
SELECTOR values for inequality, the accuracy of your results is not
guaranteed.
As with the arithmetic operators, the only legal mixed combinations of operand types
are BYTE/WORD, BYTE/DWORD, and WORD/DWORD. Whole-number
operands are treated as BYTE, WORD, DWORD, or INTEGER values as explained
in the rules of section 4.2.
If the specified relation between the operands is "true," a BYTE value of OFFH (or
1111$1111B) results. Otherwise, the result is a BYTE value of OOH (or OOOO$OOOOB).
Thus, in all cases, the result is of type BYTE, with all 8 bits set to 1 for a "true"
condition, or to 0 for a "false" condition. For example:
Values of "true" and "false" resulting from relational operations are useful in
conjunction with DO WHILE statements and IF statements, as will be seen in Chapter
6. (In the context of a DO WHILE statement or IF statement, only the least signif-
icant bit of a "true" or "false" value is used.)
These operators are used with BYTE, WORD, DWORD, or whole-number constant
operands to perform logical operations on 8, 16, or 32 bits.
NOT is a unary operator, taking one operand only. It produces a result of the same
type as its operand: each bit of the result is the ones complement of the corresponding
bit of the original value.
The remaining operators each take 2 operands, and perform bitwise "and," "or," and
"exclusive or," respectively. The bits of an AND result are 1 only where the corre-
sponding bit in each operand is 1. The bits of an OR result are 1 where the corre-
sponding bit of either operand was a I, and 0 only where both operands have a O.
The bits of an XOR result are 0 only where the corresponding bits of the operand
are the same, i.e., both 1 or both 0; the result has a 1 wherever one operand has a I
and the corresponding bit of the other operand is O.
If both operands are of the same type, the result is the same type as the operands.
As with the arithmetic and relational operators, the only legal mixed combinations
of operand types are BYTE/WORD, BYTE/DWORD, and WORD/DWORD (see
rule 2 under section 4.2). Whole-number operands are treated as BYTE, WORD, or
DWORD values as explained in rule 3 of section 4.2.
Examples are:
4-5
Expressions and Assignments PL/M-86 User's Guide
Also, notice that "true" and "false" values resulting from relational operations can
be combined meaningfully by means of logical operators.
A = (NOT B)
Operators in PLfM-86 have an implied- order (stated below) which determines how
operands and operators are grouped and analyzed during compilation.
The PLfM operators are listed in table 4-1 from highest to lowest precedence, meaning
those which take effect first are listed first. Operators in the same line are of equal
precedence and are evaluated as encountered in a left to right reading of an
expression.
The compiler first evaluates operands and operators enclosed in paired parentheses
as subexpressions, working from innermost to outermost pairs of parentheses. The
value of the sub expression is then used as an operand in the remainder of the
expression.
Table 4-1. Operators' Precedence
Operator
Operator Interpretation
Class
Relational <,<=,<>,=,>=,> Less than, less than or equal to, not equal to, equals,
greater than or equal to, greater than
4-6
PL/M-86 User's Guide Expressions and Assignments
(Parentheses are also used around both subscripts and the parameters of function or
procedure references. These are not subexpressions, but they too must be evaluated
before the remainder of the expressions or references can be evaluated at a higher
level.)
When you have more than one operator in an expression, you can evaluate the results
by beginning with the one having the highest precedence. If the operators are of equal
precedence, evaluate them left to right.
EXAMPLE REASON
The application of the precedence ranking can also be seen in the following examples:
A + B*C is equivalent to A + (B * C)
A+B-C*D is equalivent to (A + B) - (C * D)
A+B+C+D is equivalent to «A + B) + C) + D
A/B*C/D is equivalent to «A / B) * C) / D
A>B AND NOT B<C-I is equivalent to (A>B) AND(NOT(B«C- 1))
In the last four examples above, we see the application of the ··left-to-right" rule for
operators with the same precedence. In the second, third, and fifth examples, the left-
to-right rule for operators of equal precedence makes no difference in the value of
the expression. But in the fourth example, the left-to-right rule is critical.
A further example will show the action of the rules of precedence on a longer
expression
In this case, the parameter is the expression 8* B - 4.0* A*C. Floating point constants
(4.0, 2.0) are used rather than whole-number constants (4,2) because it is invalid to
combine whole-number constants with REAL variables.
The compiler first analyzes the portions of the expressions within the innermost
parentheses, then the procedure parameter above and the subexpression 2.0 * A, also
called a compound operand since its result is used in evaluating the whole expression.
I I
., r---1 ,-----,
(- B + SQRT(B*B - 4.0 * A * C»/ (2.0 * A)
In a left-to-right scan, the two operands of the first * operator are both equal to the
value of B. The operands of the second * operator are 4.0 and the value of A. The
operands of the third * operator are the results of the second evaluation (i.e., the
compound operand 4.0* A) and the value of C. The operands of the fourth * operator
are 2.0 and the value of A.
4-7
Expressions and Assignments PL/M-86 User's Guide
The subexpression 2.{)* A is now completely analyzed, but the parameter expression
still contains a minus ( - ) operator that has not been analyzed. The operands of this
operator are the result of evaluating B*B and the result of evaluating 4.0* A *C. Once
this is done, the parameter expression is analyzed and its value can be calculated.
This value does not become an operand in the overall expression. It is passed to the
procedure SQRT, which returns the square root of the parameter. This returned value
then becomes an operand in the remainder of the full original expression:
The first point is that compound operands (as shown between brackets above) have
types just as primary operands do. All of the primary operands used in the example
above were of type REAL, causing the resulting compound operands to be of type
REAL also. It is always valid for all the operands in an arithmetic expression to be
of the same type, and the result is of that type. (The only exception is that combining
BYTE values can validly create a WORD value.)
But, in an expression containing mixed data types, most combinations are not allowed.
Again, the only exception involved BYTE, WORD, and DWORD values; these may
be mixed as operands in expressions, whether constants or variables.
Mixing any other types in arithmetic, logical, or relational expressions is invalid. For
example, if F and G are INTEGER variables and Hand K are REAL variables,
then the expression.s F > K, H + G are invalid.
Due to operator precedence, some combinations can validly occur in the same
expression without being directly combined. In the following logical expression
F>GANDH<K
the subexpression F > G yields a byte value, as does the subexpression H < K. Then
the byte values are ANDed together. This expression is legal despite an apparent
mixing of types, as follows:
4-8
PL/M-86 User's Guide Expressions and Assignments
The second point is: in the absence of parentheses denoting a subexpression, the result
of a relational operation (comparison) is not allowed to become an operand in another
relational operation.
A <=X<=B
is invalid because the second < = operator would have to use the result of the first
< = operator as one of its operands.
A<=XANDX<=B
(A <= X)<=B
but the result does not have the desired meaning: A < = X becomes a byte of value
o if A is greater than X, OFFH if not. Thus, if A is 0, X is 1, and B is 2:
(0<=1)<=2
becomes (OFFH)<= 2
yields FALSE, contrary to the original intention
The third point to be made from the analytical example is that the binding of opera-
tors and operands is not the same thing as the order in which operands are evaluated.
As we have just seen, the rules of analysis completely and unambiguously specify
which operands are bound to each operator. In the expression
A + B*C
we know that Band C are the operands of the * operator, while A and the value of
B*C are the operands of the + operator. Obviously Band C must be evaluated before
the * operation can be carried out. Also, the compound operand B*C mllst be
evaluated before the + is carried out.
But it is not obvious whether B will be evaluated before C or vice versa. Indeed, A
could be evaluated before either B or C, and its value stored until the + operation is
performed.
The rules of PL/M-86 do not specify the order in which subexpressions or operands
are evaluated in each statement. This flexibility allows the compiler to optimize the
object code it produces, as discussed in Chapter 11. In most cases, the order of
evaluation makes no difference.
4-9
Expressions and Assignments PL/M-86 User's Guide
Table 4-2 is a summary of the rules for which type of arithmetic is used in each case.
The table also shows the type of the result in each case (for arithmetic operations).
The notes following the table give additional information.
Kind of Arithmetic
Variable Type Operand Type Result Notes
Arithmetic Operation
POINTER and SELECTOR variables can only appear in relational expressions, e.g., PTR11 = PTR22, which results in a BYTE value
of 0 for FALSE or OFFH for TRUE. POINTER values are compared as full iAPX 86 addresses. SELECTOR values are compared as
16-bit unsigned numbers.
NOTE: The above are the only permitted combinations of operations and operands. All other combinations are invalid; for example,
INTEGER with BYTE, REAL with WORD, and so forth. However, explicit conversions may be coded in-line using the built-in
PL/M-86 functions described in Chapter 9.
4-10
PL/M-86 User's Guide Expressions and Assignments
A + 3 *B
3-5+A
we must consider which kind of arithmetic will be used to evaluate 3 - 5, since both
operands are whole-number constants.
The answer, in this case, depends on the type of operand A. If A is of type BYTE,
WORD, or DWORD, we say that 3 - 5 is in "unsigned context." Unsigned arith-
metic is used to evaluate 3 - 5, giving a BYTE result of 254. Unsigned arithmetic
is then used to add this to A.
In this expression:
3 - 5 +500 + A
If the constant expression is not the entire expression, then its value is an operand in
the expression. The context is created by the other operand of the same operator.
If the other operand is of type BYTE, WORD, or DWORD, then each wholenumber
constant is treated as a BYTE value if it is equal to or less than 255, as a WORD
value if it is greater than 255 and equal to or less than 65,535, and as a DWORD
value if it is greater than 65,535. If the constant exceeds 4,294,967,295 it is illegal.
Unsigned arithmetic is used. In the example above, suppose the operand A has a
BYTE value. Then the constant expression 3 - 5 + 500 is in unsigned context. The
constants 3 and 5 are treated as BYTE values, and 500 is treated as a WORD value.
The operation 3 - 5 gives a BYTE result of 254, and this is extended to a WORD
value of 254 before adding 500, resulting in a WORD value of 754. It is exactly as
if the expr~ssion had been written as:
754 +A
4-11
Expressions and Assignments PLfM-86 User's Guide
Now suppose that A has an INTEGER value. In this case, the constant 3 - 5 + 500
is in signed context, and all three constants are treated as INTEGER values. This
time, signed arithmetic is used for the operation 3 - 5, which results in an INTEGER
value of - 2. Then 500 is added, and the INTEGER result is 498. It is as if the
expression had been written as:
498 +A
If the constant expression is the entire expression, then it is one of the following:
• Constant expression as right-hand part of an assignment statement: context is
created by the variable to which the expression is being assigned. Rules are given
below in section 4.7.
• Constant expression as subscript of an array variable: evaluated as if being
assigned to a WORD variable (see section 4.7).
• Constant expression in the IF part of an IF statement: evaluated as if being
assigned to a BYTE variable (see sections 6.2 and 4.7).
• Constant expression in a DO WHILE statement: evaluated as if being assigned
to a BYTE variable (see sections 6.1 and 4.7).
• Constant expression as "start," "step," or "limit" expression in an iterative DO
statement: evaluated as if being assigned to a variable of the same type as the
index variable in the same iterative DO statement (see sections 6.1 and 4.7).
• Constant expression in a DO CASE statement: evaluated as if being assigned to
a WORD variable (see sections 6.1 and 4.7).
• Constant expression as an actual parameter in a CALL statement or function
reference: evaluated as if being assigned to the corresponding formal parameter
in the procedure declaration (see sections 8.2 and 4.7).
• Constant expression in a RETURN statement: evaluated as if being assigned to
a variable of the same type as the (typed) procedure that contains the RETURN
statement (see section 4.7).
variable=expression;
4-12
PL/M-86 User's Guide Expressions and Assignments
RESULT • A + B;
the variable RESULT will have a new value, calculated by evaluating the expression
A + B.
Expression with a BYTE value. WORD variable on the left: the BYTE value is
extended by 8 high-order zero bits to convert it to a WORD value. DWORD variable
on the left: the BYTE value is extended by 24 high-order zero bits to convert it to a
DWORD value.
If the variable on the left is of any type except BYTE, WORD, or DWORD, the
assignment is illegal.
Expression with a WORD value. BYTE variable on the left: The 8 high-order bits of
the WORD value are dropped to convert it to a BYTE value. DWORD variable on
the left: the WORD value is extended by 16 high-order zero bits to convert it to a
DWORD value.
If the variable on the left is of any type except BYTE, WORD, or DWORD, the
assignment is illegal.
Expression with a DWORD value. BYTE variable on the left: the 24 high-order bits
of the DWORD value are dropped to convert it to a BYTE value. WORD variable
on the left: the 16 high-order bits of the DWORD value are dropped to convert it to
a WORD value.
If the variable on the left is of any type except BYTE, WORD, or DWORD, the
assignment is illegal.
Constant Expression
BYTE variable on the left: The constant expression is evaluated in unsigned context.
If the resulting value is less than or equal to 255, it is treated as a BYTE value and
no conversion is necessary. If the reSUlting value is greater than 255, it is converted
to type BYTE by dropping all except its 8 low-order bits.
4-13
Expressions and Assignments PL/M-86 User's Guide
WORD variable on the left: The constant expression is evaluated in unsigned context.
If the resulting value is equal to or less than 65,535, it is treated as a WORD value,
and no conversion is necessary. If the resulting value is greater than 65,535, -it is
converted to type WORD by dropping all except its 16 low-order bits.
DWORD variable on the left: The constant expression is evaluated in unsigned context.
No conversion is necessary.
INTEGER variable on the left: The constant expression is evaluated in signed context
to yield an INTEGER value. No conversion is necessary.
POINTER variable on the left: If the constant expression consists of nothing but a
single whole-number constant, the constant is treated as a POINTER value. The
whole-number constant must not be greater than 1,048,575. If the constant expres-
sion consists of anything more than a single whole-number constant, the assignment
is illegal. This is one of the three cases in which a whole-number constant can be
treated as a POINTER value. The other two cases are described in sections 3.1 and
3.6.
SELECTOR variable on the left: If the constant expression consists of nothing but a
single whole-number constant, it is treated as a SELECTOR value. The whole-number
constant must not exceed 65,535. If the constant expression consists of anything more
than a single whole-number, the assignment is illegal. This is one of two cases where
a whole-number constant can be treated as a SELECTOR value. The other case is
described in section 3.1.
REAL variable on the left: The assignment is illegal unless all values on the right are
REAL. However, the FLOAT function described in section 9.2 can be used to convert
the constant expression to a REAL value which can be assigned to that variable.
Multiple Assignment
It is often convenient to assign the same value to several variables at the same time.
This is accomplished in PL/M-86 by listing all the variables to the left of the equal
sign, separated by commas. The variables LEFT, CENTER, and RIGHT can all be
set to the value of the expression INIT + CORR with the single assignment
statement:
The order in which the assignments are performed is not predictable. There-
fore, if a variable on the left side of a multiple assignment also appears in
the expression on the right side, the results are undefined.
Embedded Assignments
A special form of assignment can be used within PL/M-86 expressions. The form of
this "embedded assignment" is:
variable: =expression
4-14
PLfM-86 User's Guide Expressions and Assignments
~
The rules of PL/M-86 do not specify the order in which subexpressions or
operands are evaluated. When an embedded assignment changes the value
of a variable that also appears elsewhere in the same expression, the results
cannot be predicted. The results depend on too many factors, e.g., the optim-
ization level you specify to the compiler (as discussed in Chapter 11).
As an example of this ambiguity, if you write:
A - (X:-X+4) + V·V + X;
you could mean either of the following interpretations:
A1 - eX+4) + V·V + (X+4);
A2 - (X+4) + V·V + X;
You should avoid this ambiguity by removing the embedded assignment from
the expression and using a separate assignment statement to achieve the
desired effect. For example, each of the above is unambiguously achieved by
the following:
(1) X· X + 4;
A1 - X + V·V + X;
( 2) X
A2 .- X + 4;
X + V·V + X 4;
( 3) A3 . X + 4 + V·V + X;
X - X + 4;
NOTE
Before using floating-point (REAL) arithmetic or assignments, refer to
Chapters 3 and 10 and Appendixes F and G, which explain many features
and restrictions that affect the result of such operations.
4-15
CHAPTER 5
ARRAYS AND STRUCTURES
5.1 Arrays
As mentioned briefly in Chapter 3, it is often desirable to use a single identifier to
refer to a whole group of scalars, and to distinguish the individual scalars by means
of a "subscript," i.e., a value enclosed in parentheses. The scalars are all the same
type. Such a list is called an array.
The elements of an array are stored contiguously, with the Oth element in the lowest
location and the last element in the highest location. (No storage is allocated for a
based array, but the elements are considered to be contiguous in memory.)
The declaration:
This causes each of the three identifiers, WIDTH, LENGTH, and HEIGHT, to be
associated with 100 array elements of type REAL, so that 300 elements of type REAL
have been declared in all. For each of these scalars, four contiguous bytes of storage
are allocated.
Subscripted Variables
To refer to a single element of a previously declared array, you use the array name
followed by a subscript enclosed in parentheses. This construct is called a
"subscripted variable."
5-1
Arrays and Strnctures PLfM-86 User's Guide
Notice that the first element of an array has subscript O-not 1. Thus, the subscript
of the last element is 1 less than the dimension specifier.
If we want to add the third element of the array ITEMS to the fourth, and store the
result in the fifth, we can write the PLfM-86 assignment statement:
Much of the power of a subscripted variable lies in the fact that the subscript need
not be a whole-number constant, but can be another variable, or in fact any
PLfM-86 expression that yields a BYTE, WORD, or INTEGER value. Thus, the
construction:
VECTOR(ITEMS(3) + 2)
refers to some element of the array VECTOR. Which element it is depends on the
expression ITEMS( 3) + 2. This value in turn depends on the value stored in
ITEMS( 3), the fourth element of array ITEMS, at the time when the reference is
processed by the running program.
If ITEMS(3) contains the value 5, then ITEMS(3} + 2 is equal to 7 and the refer-
ence is to VECTOR(7}, the eighth element of the array VECTOR.
The following sequence of statements will sum the elements of the lO-element array
NUMBERS by using an "index variable" named I, which takes on values from
o to 9:
DECLARE SUM BYTE;
DECLARE NUMBERS(10) BYTE;
DECLARE I BYTE;
SUM = 0;
DO I • 0 TO 9;
SUM • SUM + NUMBERS(I);
END;
Subscripted array variables are permitted anywhere PLfM-86 permits a variable.
They may also appear on the left side of an assignment statement if the array elements
are of a scalar type.
5.2 Structures
Just as an array allows one identifier to refer to a collection of elements of the same
type, a structure allows one identifier to refer to a collection of structure members
that may have different types. Each member of a structure has a member identifier.
A structure may have many members; see Appendix B for the correct limit. The
members of a structure are stored contiguously in the order in which they are
specified. (No storage is allocated for a based structure, but the members are
considered to be contiguous in memory.)
5-2
PL/M-86 User's Guide Arrays and Structures
Individual structure members may not be based and may not have any attributes, as
discussed in Chapter 3.
Arrays of Structures
We have already seen arrays of scalars. PL/M-86 also allows arrays of structures.
The following DECLARE statement creates an array of structures which can be used
to store SPEED and ALTITUDE (as in the previous example) for twenty
AIRPLANEs instead of one:
This declares twenty structures associated with the array identifier AIRPLANE, each
distinguished by subscripts from 0 to 19. Each of these structures consists of two
REAL scalar members. Thus, storage is allocated for 40 REAL scalars.
Given that an array can be made up of structures, and a structure can have arrays as
members, we can combine the two constructions to write:
5-3
Arrays and Structures PL/M-86 User's Guide
PAYROLLCN-1).FIRSTSHAME(K-1)
where Nand K are previously declared variables to which we have assigned appro-
priate values. This might be convenient in a routine for printing out payroll
information.
A fully qualified variable reference is one that uniquely specifies a single scalar. For
example, if we have the declarations:
It-should be noted that qualification may only be applied to variables that have been
appropriately declared. A subscript may only be applied to an identifier that has been
declared with a dimension specifier. A member-identifier may only be applied to an
identifier declared as a structure identifier. The compiler flags violations of these
rules as errors.
Unqualified and partially qualified variable references are allowed only in location
references, as discussed in Chapter 3, and in the built-in procedures LENGTH, LAST,
and SIZE, as discussed in Chapter 9.
5-4
PL/M-86 User's Guide Arrays and Structures
A partially qualified variable reference fails to refer uniquely to a single scalar even
using a subscript and/or member-identifier with an identifier. For example,
NODE(I5) and NODE(I2).SUBLIST are partially qualified variable references,
given the above declarations.
When used with the @operator, such references are taken to mean the first byte that
could fit the description. Thus @NODE(I5) is the location of the first byte of the
structure NODE(I5), which is itself an element of the array NODE. Similarly,
@NODE(I2).SUBLIST is the location of the first byte of the array
NODE(12).SUBLIST, which is itself a member of the structure NODE(12), which
in turn is an element of the array NODE.
5-5
CHAPTER 6
FLOW CONTROL STATEMENTS
This chapter describes statements that alter the sequence of execution of PL/M-86
statements and the group statements into blocks.
The present chapter discusses all four kinds of DO-blocks. Each begins with a DO
statement and includes all subsequent statements through the closing END state-
ment. The four kinds are
• The simple DO block; for example:
DO; '*
statement-O;
all statements executed, each in order *'
statement-1 ;
statement-2;
END;
• The DO CASE block; for example:
DOC A5 E selecLexpression;
case-O-statement; '* e x act 1 yon est ate men t e x e cut e d - */
case-1-statement; / * 5 e 1 e c ted b y the e x pre 5 5 ion '5 val u e */
END;
• The DO WHILE block; for example:
DOW HI l E expression_true;
statement-O; /' all ex e cut e d as Ion gas e-x pre 5 5 ion i
statement-1; /' t rue J non e when e x pre 5 5 ion i 5 f a 1 5 e.
5 *'
*/
ENDi
• The iterative DO block; for example:
6-1
Flow Control Statements PL/M-86 User's Guide
The last two blocks are also referred to as DO-loops because the executable state-
ments within them may be executed repeatedly (in sequence) depending on the
expressions in the DO statement.
As discussed with earlier charts, any DO statement may have multiple labels on it,
and the last (only) of these may appear between the word END and the next
semicolon. For example:
A: B: C: D: EM: DOj
Each DO block can contain any sequence of executable statements, including other
DO blocks. Each block is considered by the compiler as a unit, as if it were a single
executable statement. This fact is particularly useful in the DO CASE block and the
IF statement, both discussed in this chapter.
The discussions that follow describe the normal flow of control within each kind of
DO block. The normal exit from the block passes through the END statement to the
statement immediately following. These discussions assume that none of the state-
ments in the block causes control to bypass that process. A GO TO statement with
the target outside the block would be one such bypass. (GOTOs are discussed later
in this chapter.)
Simple DO Blocks
A simple DO block merely groups, as a unit, a set of statements that will be executed
sequentially (except for the effect of GOTOs or CALLs):
DO;
statement-O;
statement-1 ;
statement-n
END;
For example:
DO;
NEWSVALUE • OLDSVALUE + TEMP;
COUNT • COUNT + 1
END;
This simple DO block adds the value of TEMP to the value of OLD$VALUE and
stores it in NEWSVALUE. It then increments the value of COUNT by one.
6-2
PL/M-86 User's Guide Flow Control Statements
DO blocks may be nested within each other as shown in the following example:
able: DO;
statement-O;
statement-1 ;
baker: DO;
statement-a;
statement-b;
statement-c;
END baker;
statement-2;
statement-3;
END able;
The first DO statement and the second END statement bracket one simple DO block.
The second DO statement and the first END statement bracket a different DO block
inside the first one. Notice how indentation (using tabs or spaces) can be used to
make the sequence readable, so that it can be seen at a glance that one DO block is
nested inside another. It is recommended that this practice be followed in writing
PL/M-86 programs. See Appendix B for the number of DO blocks that can be nested.
DO CASE Blocks
A DO CASE block begins with a DO CASE statement, and selectively executes one
of the statements in the block. The statement is selected by the value of an expres-
sion. The maximum number of cases is given in Appendix B. The form of the
DO CASE block is:
DOC AS E selecLexpression;
statement-O;
statement-1 ;
statement-n;
END;
6-3
Flow Control Statements PL/M-86 User's Guide
DO CASE SCORE;
/ .. case 0
SAFETIES ..
CONVERSIONS=CONVERSIONS+1;
SAFETIES + 1 ;
/
/ .. case
case
1
2
•
•
I
I
FIELDGOALS FIELDGOALS + 1 ; /
/ . case
case
3
•
•
I
I
.
4 • I
END;
TOUCHDOWNS=TOUCHDOWNS+1;
I •
/
case
case
5
6 ·
• I
/
When execution of this CASE statement begins, the variable SCORE must be in the
range 0-6. If SCORE is 0, 4, or 5 then a null statement (consisting of only a semicolon,
and having no effect) is executed; otherwise the appropriate statement is executed,
causing the corresponding variable to be incremented.
SELECT = COUNT-5;
IF SELECT (=2 AND SELECT )=0 THEN
DO CASE SELECT;
x = X + 1; II Case 0 II
This example illustrates the use of a simple DO block as a single PL/M-86 state-
ment. The DO CASE statement can select Case 1 or Case 2 and cause multiple
statements to be executed. This is only possible because they are grouped as a simple
DO block, which acts as a single statement.
DO WHILE Blocks
DO WHILE and IF statements examine only the least significant bit of the value of
the expression. If the expression is relational, e.g., A<B, the result will have a value
of OOH or OFFH, but this is incidental; it may have any BY'FE or WORD value. If
the value is an odd number (least significant bit = 1), it will be considered "true."
If it is even (least significant bit = 0), it will he considered "false."
6-4
PLjM..86 User's Guide Flow Control Statements
A DO WHILE block begins with a DO WHILE statement, and has the form:
statement-n;
E HD;
AMOUNT • 1;
DO WHILE AMOUNT (= 3;
AMOUNT • AMOUNT + 1;
END;
The statement AMOUNT = AMOUNT + 1 is executed exactly 3 times. The
value of AMOUNT when program control passes out of the block is 4.
Iterative DO Blocks
An iterative DO block begins with an iteration statement and executes each state-
ment in order in the block, repeating the entire sequence as described in this section.
The form of the iterative DO block is:
END
The BY step-expr phrase is optional; if omitted, a step of 1 is used.
DO I • 1 TO 10;
CALL BELL;
END;
6-5
Flow Control Statements PL/M-86 User's Guide
where BELL is the name of a procedure that causes a bell to be rung. The bell is
rung ten times.
Another example shows how the index-variable can be used within the block:
AMOUNT • OJ
DO I • 1 TO 10;
AMOUNT • AMOUNT + I;
END;
The assignment statement is executed 10 times, each time with a new value for I.
The result is to sum the numbers from 1 to 10 (inclusive) and leave the sum (namely,
55) as the value of AMOUNT.
The type of counter affects two important factors in the execution flow of iterative
DOs:
a. When step-expr is evaluated.
b. What causes execution to exit the DO block.
The following steps constitute the general execution sequence of an iterative DO block,
with BYTE, WORD, or INTEGER variables and expressions in the DO itself. Type
is mentioned only for steps where it matters, i.e., where the actions or consequences
are different for different types. Where the INTEGER case is different, it is described
in parentheses. The discussion following this description summarizes all the rules and
their results.
1. The start-expr is evaluated and assigned to counter.
2. The limit-expr is evaluated and compared with counter. (If these are INTEGER
type, then step-expr is also newly evaluated at this time.)
a. If counter is greater than limit-expr, execution exits the DO and passes to the
statement following the next END (unless step-expris a negative INTEGER;
if so, the exit occurs only if counter is less than limit-expr.)
b. Otherwise, the statements within the DO block are executed in order until
the END statement is reached.
c. At the END, a step-exprof type BYTE or WORD is newly evaluated.
3. The counter is incremented by the value of step-expr. For BYTE or WORD
counters, if the new value is less than the old value (due to modulo arithmetic as
explained below), the loop is exited immediately.
Otherwise, control returns to step 2 above.
(An 8-bit byte can represent numbers no larger than 1111111lB (255 decimal). The
largest number a 16-bit word can represent is I111111111111111B, which is 65535
decimal. If you add 1 to these values, you get o. Thus, the new counter can be less
than the old.)
6-6
PLfM-86 User's Guide Flow Control Statements
These rules and their consequences can be summarized in two broad cases:
A. If you start with a non-negative step-expr, then the loop is exited as soon as any
one of the following becomes true:
1. The new counter is greater than the new limit-expr.
2. An INTEGER step-expr becomes negative AND the new counter is still less
than the new limit-expr.
3. A BYTE or WORD step-expr causes a lower counter than the one just used.
B. If you start with a negative INTEGER step-expr, then the loop is exited as soon
as either of the following two conditions occurs:
1. The new counter is less than the new limit-expr.
2. The new step-expr becomes non-negative AND the new counter is greater
than the new limit-expr.
The reserved word THEN and the statement following it are required and are called
the "THEN part." The reserved word ELSE and the statement following it are
optional, and are called the "ELSE part."
The IF statement has the following effect: first expression is evaluated as if it were
being assigned to a variable of type BYTE. If the result is "true" (rightmost bit is 1)
then statement-a is executed. If the result is "false" (rightmost bit is 0), then
statement-b is executed. Following execution of the chosen alternative, control passes
to the next statement following the IF statement. Thus, of the two statements
(statement-a and statement-b) one and only one is executed.
6-7
Flow Control Statements PL/M-S6 User's Guide
Here, RESULT is assigned the value of NEW or the value of OLD, whichever is
greater. This code causes exactly one of the two assignment statements to be executed.
RESULT always gets assigned some value, but only one assignment to RESULT is
executed.
In the event that statement-b is not needed, the ELSE part may be omitted entirely.
Such an IF statement takes the form:
For example, the following sequence of PL/M-86 statements will assign to INDEX
either the number 5, or the value of THRESHOLD, whichever is larger. The value
of IN IT will change during execution of the IF statement only if THRESHOLD is
greater than 5. The final value of INIT is copied to INDEX in any case:
IHIT • 5;
IF THRESHOLD) IHIT THEH IHIT • THRESHOLD;
IHDEX • INIT;
The power of the IF statement is enhanced by using DO blocks in the THEN and
ELSE parts. Since a DO block is allowed wherever a single statement is allowed,
each of the two statements in an IF statement may be a DO block. For example:
IF A • B THEH
DO;
EQUALSEVEHTS • EQUALSEVENTS + 1;
PAIR$VALUE • A;
BOTTOM • B;
END;
ELSE
DO;
UHEQUAL$EVENTS • UNEQUAL$EVEHTS + 1;
TOP • A;
BOTTOM • B;
END;
Nested IF Statements
Any IF statement (including the ELSE part, if any) may be considered a single
PL/M-86 statement (although it is not a block). Thus, the statement to be executed
in a THEN or an ELSE clause may in fact be another IF statement.
6-8
PL/M-86 User's Guide Flow Control Statements
I F expression-1 THE Ii
IF expression-2 THE H
I F expression-3 THE H statement-a;
Here we have three levels of nesting. Note that statement-a will be executed only if
the values of all three expressions are ·'true.," Thus, the above is equivalent to:
Notice that the above example of nesting does not have an ELSE part. When using
nested IF statements, it is important to understand the following important rule of
PLJM-86:
A set of nested IF statements may have only one ELSE part, and it belongs to the
innermost (that is, the last) of the nested IF statements.
When an IF statement is nested within the THEN part of an outer IF statement, the
outer IF statement may not have an ELSE part.
I F expression-1 THE H
I F expression-2 THE H statement-a
E L S E statement-b i
is legal and means that if the values of both expression-1 and expression-2 are "true,"
then statement-a will be executed. If the value of expression-1 is "true" and the value
of expression-2 is "false," then statement-b will be executed. If the value of
expression-1 is "false," neither statement-a nor statement-b will be executed, regard-
less of the value of expression-2.
I F expression-1 THE H
DO:
I F expression-2 THE H statement-a;
E L S E statement-b i
E HD i
This construction is much more readable and offers less opportunity for error.
If the intention is for the ELSE part to belong to the outer IF statement, then the
nesting must be done by means of a DO block:
I F expression-1 THE H
DO i
I F expression-2 THE H
statement-a;
E HD i
E L S E statement-b;
Note that the meaning of this construction differs completely from the previous one.
6-9
Flow Control Statements PLfM-86 User's Guide
I F expression-1 THE H
I F expression-2 THE H
I F expression-3 THE H statement-a;
E L S E statement-b;
E L S E statement-c; /* illegal statement */
E L S E statement-d; /* illegal statement * /
This construction is illegal because only one ELSE part is allowed. If the intention is
for the ELSE parts to match the IF parts as indicated by the indenting, the nesting
must be done with DO blocks, as follows:
I F expression-1 THE H
DO;
I F expression-2 THE H
DO; I F expression-3 THE H statement-a;
EL SE statement-b;
E H D;
E L S E statement-c;
EHD;
E L SE statement-d;
Sequential IF Statements
Consider the following example. An ASCII-coded character is stored in a BYTE
variable named CHAR. If the character is an A, we want to execute statement-a. If
the character is a B, we want to execute statement-b. If the character is a C, we want
to execute statement-c. If the character is not A, B, or C, we want to execute
statement-x. The code for doing this could be written as follows, using IF statements
that are completely independent of one another:
This sequence is inefficient because all four IF statements (six tests in all) will be
carried out in every case, which is wasteful when one of the earlier tests succeeds.
We need to test for 'A' in all cases. But we need to test for 'B' only if the test for 'A'
- fails and we need to test for 'C' only if both previous tests fail. Finally, if the tests
for 'A', 'B', and 'C' all fail, no further tests are needed-we must execute
statement-x. To improve the code, we rewrite it as follows:
I F C H A R • \ A' THE H statement-a;
E L S ElF CH A R • 'B' THE H statement-b;
E L S ElF CH A R • 'C' THE H statement-c;
E L S E statement-x;
6-10
PL/M-86 User's Guide Flow Control'Statements
Notice that this sequence is not a case of "nested IF statements" as described in the
preceding section. IF statements are said to be nested only when one IF statement is
inside the THEN part of another. Here, we have IF statements inside the ELSE parts
of other IF statements. This construction is called "sequential IF statements." It is
equivalent to the following:
GOT 0 label;
For example:
GOTO ABORT;
The appearance of label in a GOTO statement is not a "label definition"-it is a
label reference.
The reserved word GOTO can also be written GO TO, with an embedded blank.
For reasons discussed in Chapter 7, GOTO statements are restricted. The only possi-
ble GOTO transfers are the following:
• From a GO TO statement in the outer level of some block to a labeled statement
in the outer level of the same block.
• From a GOTO statement in an inner block to a labeled statement in the outer
level of an enclosing block (not necessarily the smallest enclosing block). However,
if the inner block is a procedure block, the transfer may only be to a statement
in the outer level of the main program module.
• From any point in one program module to a labeled statement in the outer level
of the main program module. To jump to such a label, you must declare the label
to have "extended scope," i.e., declare it PUBLIC in the main module and
EXTERNAL in the module containing the GOTO.
The use of GOTOs is necessary in some situations. However, in most situations where
control transfers are desired, the use of an iterative DO, DO WHILE, DO CASE,
IF, or a procedure activation (see Chapter 8) is preferable. Indiscriminate use of
GOTOs will result in a program that is difficult to understand, correct, and maintain.
6-11
Flow Control Statements PL/M-86 User's Guide
The CALL statement is used to activate an untyped procedure (one that does not
return a value).
The RETURN statement is used within a procedure body to cause a return of control
from the procedure to the point from which it was activated.
6-12
CHAPTER 7
BLOCK STRUCTURE AND SCOPE
This chapter is intended to clarify the meaning of outer level and the concept of
scope, including the use of the linkage attributes, PUBLIC and EXTERNAL.
The outer level of a block means statements (or labels) contained in the block but
not contained in any nested blocks. The term "exclusive extent" also has this meaning.
The inner level, or "inclusive extent," includes this outer level and all nested blocks
as well.
A block "at the same lever' as another block means both are contained by exactly
the same outer blocks.
The scope of an object means those parts of a program where its name, type, and
attributes are recognized (i.e., handled according to a given declaration). An object
means a variable, label, procedure, or symbolic (named) constant (i.e., a compilation
constant or execution constant as discussed in Chapter 3). A program is the complete
set of modules that are ultimately executed as a unit.
These definitions are explained further by the text and examples that follow.
Beyond the advantages of modularity, simplicity, and clarity, the nesting of blocks
serves another very basic purpose: names declared at an outer level are known to all
statements of all nested blocks as well.
You can always declare a new meaning for any such name within a nested simple-DO
or procedure block, thereby cutting off its earlier meaning for this block. But if you
don't choose this option, its meaning is established by a single declaration at an outer
level. (The only objects that don't require declarations prior to use are labels and re-
entrant procedures.)
In figure 7-1, everything inside the solid line constitutes the inclusive extent of block
MMM (in this case, module MMM). KK is known throughout this block, including
within all nested blocks.
Everything inside the dashed line constitutes the inclusive extent of block SORT.
JJ and II are known throughout this block, but not outside it, that is, not before the
label SORT or after the END SORT statement.
Everything inside the dotted line constitutes the inclusive extent of block FIND. Since
this is not a simple-DO or procedure block, declarations are not allowed. All prior
declarations shown are available for use within FIND.
7-1
Block Structure and Scope PLfM-86 User's Guide
SO R T :
r----------------------------
DO;
DECLARE (JJ,II) INTEGER;
DO JJ = 1 TO 127;
CURRENT.KEY = RECORD(JJ).KEY;
CURRENT.INFO = RECORD(JJ).INFOj
· . !-.1•••=: .. ~ .J. i ............................................ .
FIND: . DO WHILE II > 0 AND .
RECORD(II-1).KEY > CURRENT.KEY;
· RECORD(II).KEY = RECORD(II-1).KEY;
· RECORD(II). INFO = RECORD(II-1).INFOj:
II = 11-1;
: END FIND; :
c
RECOR D( i' i )" : k' EY•.~ •• if R'R' E'N T' : K' E'Y' ; ........................ .
RECORD(II),INFO = CURRENT. INFO;
END;
END SORT;
-----------------------------
'·Instructions here would write out
data from the records,·'
END MMM; '·End of module·'
The shaded area is the exclusive extent (the outer level) of block SORT. The unshaded
area within SORT is the exclusive (and inclusive) extent of block FIND. To the
instructions within the FIND block, SORT's exclusive extent is an outer level. The
outermost level (or module level) is the area outside the solid lines enclosing the
SORT block.
In any given block, a known name cannot be redeclared at the same level as its
original declaration. A new declaration is permitted inside a nested simple-DO or
procedure block, where it automatically identifies a new object despite the existence
of the same name at a higher level. The new object will be the only one known by
this name within its block, and it will be unknown outside its block, where the prior
name maintains its meaning. These observations also apply when a name is redeclared
in another block at the same level as. the block containing the original deClaration.
7-2
PL/M-86 User's Guide Block Structure and Scope
SORT:
When a name is declared only in a separate block at the same level, there is no way
to access it except in that block where it is declared. The definition is not at an outer
level to the block in which you are now programming. Any local declaration you
supply will establish a new separate object whose values bear no relation to those of
the other.
The reason for these rules, as for many in programming, is that there must be no
ambiguity about what address/location is meant by each name in the program. The
declaration rules above give you freedom to choose whatever names seem appropriate
within a given block, without interfering with exterior uses of them. But when you
re-declare a name, its outer-level meaning is inaccessible until execution exits the
block containing the new declaration. For example:
A: DO;
DECLARE X, Y, Z BYTE;
L1: X-2;
Y-X;
Z- X;
7-3
Block Structure and Scope PL/M-86 User's Guide
B: DO,
DECLARE X, Y BYTE;
X- 3 ;
Y .. X ;
L2: Z=X;
EHD B;
L3 : '·At this point, X=2, Y-2, Z=3, because the
value of the redeclared X was use d t 0 f ill
Z*'
'·If statement L2 were outside the loop labeled
B, then Z would be 2 because the outer X
value would be used.·'
By ""extend the scope," we mean make the names available for use in modules other
than the one where they are defined. (The names are already available to nested
blocks in this module.) To be specific, this includes names for variables, labels,
procedures, and execution constants.
causes a byte to be allocated, named FLAG, and its address made known to any other
module where the following declaration occurs:
EHD SUMMER;
7-4
PLfM-86 User's Guide Block Structure and Scope
2. Only one may appear on any declaration, and only once. Thus:
4. Names may be declared EXTERNAL only if they are also declared PUBLIC in
a different module of the program. The EXTERNAL attribute is essentially a
request to use a PUBLIC address. An EXTERNAL without a PUBLIC is a
dead letter. Lack of a definition elsewhere will result in a link-time error.
5. Where the name is declared EXTERNAL, it must be given the same type as
where it is declared PUBLIC. Any contradiction of type would violate the inten-
tion to use the location(s) and content(s) defined elsewhere. If the name is declared
PUBLIC and has the DATA attribute, all EXTERNAL declarations must also
use DATA.
6. Similarly, names declared EXTERNAL must not be given a location (using the
AT clause), or an initialization (using DATA or INITIAL). Such usage would
contradict the fact that names are being defined in another module. However, in
the module where this name is declared PUBLIC, the use of AT, DATA, or
INITIAL is allowed.
7. Neither PUBLIC nor EXTERNAL may be applied to a name that is based. For
example:
NOTE
The PL/M-86 compiler will generate external records only for items that
are actually referenced in the program.
7-5
Block Structure and Scope PL/M-86 User's Guide
Following these rules will permit consistent and reliable execution of programs using
names with extended scope. A PUBLIC definition occurring in one module will then
be used by all related references to that name in separate modules; that is, references
which declare the name' EXTERNAL. The diagram below illustrates this:
(It 0D1 : DO
DECLARE V1 BYTE PUBLIC;
EHD MOD1;
MOD2: DO;
DECLARE V1 BYTE EXTERHAL;
GG4: PROCEDURE PUBLIC;
EHD GG4;
EHD MOD2;
Both references to V 1 will use the same definition (location) for VI, namely, the
definition in module MODI. Similarly, if any module needed to call procedure QQ4,
it would first need a declaration like this:
One consequence is that a label is unknown outside the block where it is declared. As
discussed in Chapter 1, a label is either declared explicitly at the beginning of a
simple-DO or procedure block, or the compiler considers it to be declared there as
soon as it is defined by use anywhere in the block. Therefore, the discussion of what
names are known in which blocks applies directly to labels as well as to other names.
The label on a block is not part of the block it names. For example, the name on the
DO enclosing the module itself is not part of that DO; it merely names it. For nested
blocks, a label is again not part of the block it names, but belongs instead to the outer
level as part of that first enclosing block.
If a name used as a label on a block is defined inside that block, it will name a new
thing, be it label, variable, or constant. There will be no confusion with the outer
label name. This fact leads to important restrictions on the use of the GOTO state-
ment:
1. It is impossible for a GOTO to transfer control from an outer block to a labeled
statement inside a nested block.
2. Moreover, a GOTO can transfer control from one block to another in the same
module only if the target block encloses the one containing the GOTO (and only
if the name of that target label is not declared in the nested block.)
7-6
PL/M-86 User's Guide Block Structure and Scope
Furthermore, a label with the PUBLIC attribute is permitted only in the main module.
(This has the interesting consequence of forcing all other transfers of control-that
is, those not involving a return to the main module-to use procedure calls. This
favors the development of orderly, modularized, traceable programs.)
(Recall that only labels at the outer level of a main program may be declared
PUBLIC.)
Given the program structure and declarations shown in figure 7-3, the only valid
GOTO transfers are shown in figure 7-4. A single-headed arrow means the transfer
is valid only in the direction shown. A double-headed arrow means that a GO TO can
be used in either direction.
MAIN: DOj
DECLARE (LAB33, LAB77) LABEL PUBLICj
DECLARE IT BYTEj
LAB33:
DOj
ENDj
LAB77:
DO WHILE IT > 0;
ENDj
END MAlHi
7-7
Block Structure and Scope PLfM-86 User's Guide
MOD1: DO;
P 1: PROCEDURE;
DECLARE (LAB33,LAB77) LA~EL EXTERNAL;
L 1: • • • ,
DO;
DECLARE KO BYTE;
P2: PROCEDURE
L2: .,
END P2;
L3 : . ,
END P1;
END MOD1;
/I10D2: DO;
P4: PROCEDURE;
DECLARE (LAB33,LAB77) LABEL EXTERNAL;
L4:
L5 : i
DO;
L6:
ENDj
L7:
END P4j
L8 :
END MOD2j
Figure 7-3. Sample Program Modules Illustrating Valid GOTO Usage (Cont'd.)
7-8
PLjM-86 User's Guide Block Structure and Scope
Figure 7-4 illustrates legal GOTO transfers that are the only transfers permitted
among the given labels in figure 7-3.
LAB33
OR
LAB77
7-9
CHAPTER 8
PROCEDURES
The use of procedures forms the basis of modular programming. It facilitates making
and using program libraries, eases programming and documentation, and reduces the
amount of object code generated by a program. The following sections review how to
declare and activate procedures.
8. 1 Procedure Declarations
You must declare procedures, just as you must declare variables. Thereafter, any
reference to a procedure must occur within the scope defined by the procedure decla-
ration. Also, a procedure may not be used (called, or invoked in an expression) until
after the END statement of the procedure declaration (unless re-entrant-see
section 8.5).
DOOR.CHECK:PROCEDUREj
IF FRONT.DOOR.LOCKED AND SIDE.DOOR.LOCKED
THEN CALL POWER.ONi
ELSE CALL DOOR.ALARMi
END DOOR.CHECKi
where POWER$ON and DOOR$ALARM are procedures declared elsewhere in the
same program.
NOTE
The name in a PROCEDURE statement has the same appearance as a label
definition-but it is not considered a label definition, and a procedure name
is not a label. PROCEDURE statements may not be labeled.
The name is a PL/M.::86 identifier, which is associated with this procedure. The scope
of a procedure is governed by the placement of its declaration in the program text,
just as the scope of a variable is governed by the placement of its DECLARE state-
ment (see Chapter 7 for a detailed description). Within this scope, the procedure can
be activated by the name used in the PROCEDURE statement.
8-1
Procedures PL/M-86 User's Guide
As in a DO block, the identifier in the END statement has no effect on the program,
but helps legibility and debugging. If used, it must be the same as the procedure
name.
The parameter list and the type are discussed in the following two sections.
Parameters
Formal parameters are non-based scalar variables declared within a procedure
declaration; their identifiers appear in the parameter list in the PROCEDURE
statement. The identifiers in the list are separated by commas and the list is enclosed
in parentheses. No subscripts or member-identifiers are allowed in the parameter list.
If the procedure has no formal parameters, the parameter list (including the
parentheses) is omitted from the PROCEDURE statement.
When a procedure that has formal parameters is activated, the CALL statement or
function reference contains a list of actual parameters. Each actual parameter is an
expression whose value is assigned to the corresponding formal parameter in the
procedure before the procedure begins to execute.
For example, the following procedure takes four parameters, called PTR, N, LOWER,
and UPPER. It examines N contiguously stored BYTE variables. The parameter
PTR is the location of the first of these variables. If any of these variables is less than
the parameter LOWER or greater than the parameter UPPER, the ERRORSET
procedure (declared elsewhere in the program) is activated:
RANGE$CHECK: PROCEDURE(PTR,H,LOWER,UPPER)i
DECLARE PTR POIHTERi
DECLARE (H,LOWER,UPPER,I)BYTEi
DECLARE ITEM BASED PTR(1)BYTE;
DO I .. 0 TO N-1i
IF (ITEM(I) < LOWER) OR (ITEM(I) > UPPER)
THEN CALL ERRORSET;
I'ERRORSET is a procedure declared eisewhere'l
END;
END RANGE$CHECK;
Notice that the array ITEM is declared to have only one element. Since it is a based
array, a reference to any element of ITEM is really a reference to some location
relative to the location represented by PTR. In writing the procedure
RANGE$CHECK, we must supply a dimension specifier above zero for ITEM so
that references to ITEM can be subscripted. But it does not matter what the dimen-
sion specifier is. We arbitrarily use 1 here.
Having made this declaration, suppose that we have 25 variables stored contiguously
in an array called QU ANTS. We want to check that all of these variables have values
within the range defined by the values of two other BYTE variables, SMALL and
LARGE.
8-2
PL/M-86 User's Guide Procedures
We write:
Notice how the use of a based variable, with the base passed as a parameter, allows
the procedure to have its own unchanging name (ITEM) for a set of variables which
may be a different set each time the procedure is activated.
When a procedure has more than one parameter, PL/M -86 does not guarantee
the order in which actual parameters will be evaluated when the procedure
is activated. If one actual parameter changes another actual parameter, the
results are undefined. This can occur if an expression used as an actual
parameter contains an embedded assignment or function reference which
changes another actual parameter for the same procedure. See the next
caution also.
A typed procedure, also called a junction, has a type in its PROCEDURE statement:
BYTE, WORD, DWORD, INTEGER, REAL, POINTER, or SELECTOR. Such
a procedure returns a value of this type, which is used in an expression or stored as
the value of a variable. The procedure is activated by using its name as an operand
in an expression; this special type of variable reference is called a ""function
reference. "
When the expression is processed at run time, the function reference causes the
procedure to be executed. The function reference itself is then replaced by the value
returned by the procedure. The expression containing the function reference is then
evaluated, and program execution continues in normal sequence.
Like an untyped procedure, a typed procedure may have parameters.. They are handled
as described in the previous section.
The body of a typed procedure must always contain a RETURN statement with an
expression, as explained later in this chapter.
8-3
Procedures PLfM-86 User's Guide
The two forms of procedure activation depend on whether the procedure is typed or
untyped. An untyped procedure is activated by means of a CALL statement, which
has the form:
CAL L name
or:
name
or
8-4
PL/M-86 User's Guide Procedures
In both forms of procedure activation, the elements of the parameter list are called
"actual parameters" to distinguish them from the uformal parameters" of the proce-
dure declaration. At the time of activation, each actual parameter is evaluated and
the result is assigned to the corresponding formal parameter in the procedure decla-
ration. Then, the procedure body is executed. Any PL/M-86 expression may be an
actual parameter if its type is the same as that of the corresponding formal
parameter.
The actual parameter list in a procedure activation must also match the formal
parameter list in the procedure declaration-that is, it must contain the same number
of parameters of the same type in the same order. If the procedure is declared without
a formal parameter list, then no actual parameter list can be used in the activation.
As in expression evaluation and assignment statements (see Chapter 4), a few type
conversions are performed automatically when necessary in activating and returning
from a procedure. The built-in explicit type conversion procedures of Chapter 9 can
also be used to force the value of an expression to a desired type.
The CALL statement, in the form shown _above, activates an untyped procedure by
its name. It is also possible to activate an untyped procedure by its location. This is
done by means of a CALL statement with the form:
The identifier may not be subscripted, though it may be a structure reference. It must
be a fully qualified POINTER or WORD type variable reference, and its value is
assumed to be the location of the entry-point of the procedure being activated.
NOTE
Calls through 32-bit POINTERs will be translated into "long" calls while
those through 16-bit WORDs or POINTERs (in the SMALL case) will be
translated into "short" calls (relative to the current code segment). The
compiler will issue a warning if the wrong addressing type is used to gain a
procedure address for later indirect calls.
A normal CALL uses the name of the procedure; the compiler checks to make sure
that the correct number of parameters is supplied and performs automatic type
conversion on the actual parameters.
When the CALL statement uses a location, the compiler does not check the number
of parameters or perform type conversion. If the number of parameters is wrong or
if an actual parameter is not of the same type as the corresponding formal parameter,
the results are unpredictable.
8-5
Procedures PLfM-86 User's Guide
RETURN;
or
The first form is used in an untyped procedure. The second form is used in a typed
procedure. The value of expression becomes the value returned by the procedure. It
is evaluated as if it were being assigned to a variable of the same type as used on the
PROCEDURE statement.
Examples
1. The following is a typed procedure declaration:
LOW • 3.0;
HIGH • 4.0;
MEAN • AVG (SMALL, LARGE);
The affect would be to assign the value 3.5 to MEAN.
2. The following is an untyped procedure:
8-6
PL/M-86 User's Guide Procedures
SUM-Oj
DO I - 0 TO H;
SUM - SUM + ARRAV(I);
E HD;
RETURN SUM;
END SUM.ARRAV;
This procedure returns the sum of the first N + I elements (from the Oth to the
Nth) of a BYTE array pointed to by PTR. Notice that ARRAY is declared to have
I element. Since it is a based variable, no space is allocated for it. It must be declared
as an array (with a non-zero dimension) so that it can be subscripted in the iterative
DO block. The choice of I as the constant in the dimension specifier is arbitrary and
does not restrict the value of N that may be supplied when the procedure is activated.
The procedure could be used as follows to sum the elements of a IOO-element BYTE
array named PRICE, and to assign the sum to the variable TOTAL:
TOTAL - SUM.ARRAV(,PRICE,99);
NOTE
The PL/M-86 compiler will only generate external records for items that
are actually referenced in the program.
For example, we can alter the procedure AVG (from example I above) by giving it
the PUBLIC attribute:
8-7
Procedures PL/M-86 User's Guide
The INTERRUPT attribute allows you to define a procedure to handle some condi-
tion signaled by an iAPX 86 interrupt, e.g., from a peripheral device. A procedure
with this attribute is activated when the corresponding interrupt signal is received in
the iAPX 86-based system. The PLJM-86 statement CAUSE$INTERRUPT
(constant) can also be used to initiate an interrupt signal (see Chapter 10).
Note that the following discussion applies only to interrupt procedures; interrupt tasks
are discussed in Appendix G.
The INTERRUPT attribute can be used only in declaring an untyped procedure with
no parameters at the outermost level of a program module. It must be declared
PUBLIC or EXTERNAL (and optionally REENTRANT). The form is
INTERRUPT n
where n is any decimal number from 0 to 255. Each number can only be used once
in a program. Each such procedure is then referred to as an interrupt procedure.
Such a procedure is necessary if you wish to provide non-default handling of excep-
tion conditions arising in floating-point arithmetic (see appendixes F and G).
The following discussion of the iAPX 86 interrupt mechanism clarifies how interrupt
procedures work. Additional information can be found in Appendix G.
The iAPX 86 interrupt mechanism has two states: enabled or disabled. The ENABLE
statement allows interrupts to- take affect and the DISABLE statement prevents them
from having any affect. The HALT statement also enables interrupts. (The state of
the iAPX 86 interrupt mechanism upon initialization is determined by the operating
system.)
When some peripheral device sends an interrupt to the iAPX 86 CPU, it is ignored
if the interrupt mechanism is disabled. If interrupts are enabled, the interrupt is
processed as follows:
1. The CPU completes any instruction currently in execution.
2. The CPU sends an "acknowledge interrupt" signal, then the interrupting device
sends its interrupt number.
3. The interrupt mechanism is disabled. This prevents any other device from
interfering.
4. Control passes to the interrupt procedure whose number matches the number
sent by the peripheral device. If no such procedure has been established, the results
are undefined, since the vector that transfers control may be uninitialized.
8-8
PLJM-86 User's Guide Procedures
5. When the procedure is through (by executing a RETURN or reaching the END
of the procedure), the interrupt mechanism is enabled so other devices may be
serviced, and control returns to the point where the interrupt occurred.
It is possible (as with other untyped procedures) for the procedure to terminate
by executing a GOTO with a target outside the procedure in the outer level of
the main program module. In this case, control will never be returned to the point
where the program was interrupted, and interrupts will not be enabled
automatically.
END HITEMPj
IWARNING I
If using an interrupt procedure that will call another interrupt procedure,
you must manually extend the length of the -stack storage, as the compiler
allocates only enough space to save one procedure. See Appendix G and use
the LINK and LOC sequence (the Family Utilities User's Guide) for more
information.
NOTE
Unlike PL/M-80, PL/M-86 interrupt routines activated with a CALL state-
ment do not alter the interrupt enable status. This means that termination
of the procedure by means of a RETURN statement or the END statement
will not automatically enable interrupts.
8-9
Procedures PL/M-86 User's Guide
This ability is desirable in two circumstances: (1) if your procedure (PROCl) activates
itself (called direct recursion), or (2) if your procedure activates another procedure
(PROC2) that will reactivate PROCI before PROCI has finished its original
processing (called indirect recursion).
When you use the attribute REENTRANT in declaring a procedure, its variables
are not stored with other variables in the data section, but are stored on the stack.
Thus preserved, each set can be used independently by each invocation of the proce-
dure.
Multiple sets of variables may therefore need to be stored on the stack during recur-
sive use of such procedures. You must be sure to specify (at relocation and link time)
a stack size large enough for all such storage needed by all multiple invocations that
may be active at one time.
8-10
PL/M-86 User's Guide Procedures
• Any procedure that is activated by a reentrant procedure should also have the
REENTRANT attribute.
In other words: if there is any possibility that a procedure can be activated while it is
already running, it should be reentrant.
• The REENTRANT attribute cannot be used in the same declaration as the
EXTERNAL attribute. (It may be used with the PUBLIC attribute.)
• The REENTRANT attribute may only be used in a PROCEDURE statement
at the outer level of a module (discussed in Chapter 7).
• A procedure declaration with the REENTRANT attribute may not have another
procedure declaration nested inside it.
8-11
CHAPTER 9
BUILT-IN PROCEDURES,
FUNCTIONS. AND VARIABLES
Built-in procedures, functions, and variables act as if they were declared in an all
encompassing global block invisible to the programmer.
These identifiers are subject to the rules of scope. This means the name of a built-in
procedure or variable can be declared to have a local meaning within the program.
Within the scope of such a declaration, the built-in is unavailable. This distinguishes
these identifiers from reserved words, listed in Appendix A, which cannot be used as
identifiers in declarations.
The WORD value returned is the number of elements in the array-that is, it is
equal to the dimension specifier in the array declaration.
If the array is not a structure member, then the reference must be an unqualified
variable reference. If the array is a structure member, then the reference is a partially
qualified variable reference (see section 5.3). For example, given the declaration:
9-1
Built-ID Procedures, Functions, and Variables PL/M-86 User's Guide
then all of the following function references are correct and return the value 3.
LENGTH(LIST(O).IHFO)
LEHGTH(LIST(1).IHFO)
LEHGTH(LIST(2). INFO)
LEHGTH(LIST(3).IHFO)
In other words, the subscript for the array LIST is irrelevant wheha member-identifier
is supplied, since the arrays within the structures are all the same length. PL/M-86
allows a "shorthand" form of partially qualified variable reference in the LENGTH,
LAST, and SIZE function references. For example:
LEHGTH(LIST.IHFO)
is a valid function reference and returns the value 3.
LAST is a WORD function that returns the subscript of the last element in an array.
It is activated by a function reference with the form:
LAS T (variable-ref)
where
variable-ref must be a non-subscripted reference to an array.
The WORD value returned is the subscript of the last element of the array. Note
that for a given array, LAST will always be one less than LENGTH.
SIZE is a WORD function that returns the number of bytes occupied by an array or
structure. It is activated by a function reference with the form:
5 I Z E ( variable-ref)
where
variable-ref is a fully qualified, partially qualified, or unqualified refer-
ence to any scalar, array, or structure. The variable-ref may
not be an EXTERNAL declaration that uses the implicit
dimension specifier (see section 3.2).
The WORD value returned is the number of bytes required by the object referenced.
If the reference is fully qualified, it refers to a scalar, and the value is the number of
bytes required for the scalar. If the reference is unqualified, it refers to an entire
structure or array, and the value is the total number of bytes required for the struc-
ture or array.
9-2
PL/M-86 User's Guide Built-In Procedures, Functions, and Variables
function-name ( expression)
where
function-name has a type and expression has a value.
In table 9-1, each function name is followed by its type, the expression type expected,
the purpose of the function, and the nature of the value it returns to the expression
that invoked it.
FIX INTEGER REAL Converts REAL value INTEGER value modulo 32768,
to INTEGER value i.e., within range ± 32767
(rounds toward zero)
9-3
Built-In Procedures, Functions and Variables PL/M-86 User's Guide
UNSIGN WORD INTEGER Converts an INTEGER The bit pattern is unchanged but
value to a WORD value can now be used in WORD
expressions
LOW and HIGH are BYTE functions that convert WORD values to BYTE values,
or WORD functions that convert DWORD values to WORD values. They are
activated by function references with the forms:
LOW (expression)
H I GH ( expression)
where
expression has a DWORD, WORD, or BYTE value.
If expression has a DWORD value, LOW returns the value of the low-order (least
significant) word of the expression value whereas HIGH returns the value of the
high-order (most significant) word of the expression value.
If expression has a WORD value, LOW returns the value of the low-order (least
significant) byte of the expression value whereas HIGH returns the value of the high-
order (most significant) byte of the expression value.
If expression has a BYTE value, then LOW will return this value unchanged.
However, HIGH will return o.
D 0 UB L E expression
where
expression has a BYTE, WORD, or DWORD value.
9-4
PL/M-86 User's Guide Built-In Procedures, Functions and Variables
If expression has a BYTE value, the function appends 8 high-order zero bits to convert
it to a WORD value and returns this WORD value. If expression has a WORD
value, the function appends 16 high-order zero bits to convert it to a DWORD value
and returns this value. If expression has a DWORD value, the function returns it
unchanged.
FLO AT ( expression)
where
expression has an INTEGER value.
FLOAT converts the INTEGER value to the corresponding REAL value and returns
this REAL value.
F I X ( expression)
where
expression has a REAL value.
FIX rounds the REAL value to the nearest INTEGER. If both INTEGERs are
equally near, FIX rounds to the even one. The resulting INTEGER value is then
returned. Thus, FIX(1.4) would result in the INTEGER value 1, FIX( -1.8) in -2,
FIX(3.5) in 4, and FIX(6.5) in ~.
If the result calculated by FIX is not within the implemented range of INTEGER
values, the result is undefined.
NOTE
FIX is affected by your choice of rounding mode-see section 10.5. The above
examples assume the default mode, which is "round to nearest or even."
I HT ( expression)
where
expression has a BYTE or WORD value.
INT interprets the BYTE or WORD value as a positive number and returns the
corresponding INTEGER value.
If the result calculated by INT is not within the implemented range of INTEGER
values, the result is undefined.
9-5
Built-In Procedures, Functions and Variables PL/M-86 User's Guide
S I G HE D (expression)
where
expression has a WORD or BYTE value.
This means that if the highest-order (most significant) bit of the WORD valued is a
0, SIGNED interprets the WORD value as a positive number and returns the corre-
sponding INTEGER value. For example:
SIGHED (0000$0000SOOOOS0100B)
But if the highest-order bit of the WORD value is aI, SIGNED returns a negative
INTEGER value whose absolute magnitude is the two's complement of the WORD
value. For example:
UHS I G H (expression)
where
expression has an INTEGER value.
If the INTEGER value is positive, then the WORD value will be numerically the
same as the INTEGER value. But if the INTEGER value is negative, then the
WORD value will be the two's complement of the absolute magnitude of the
INTEGER value. For example:
UHSIGH(-4)
1111$ 1 1 1 1 S 1 1 1 1 S 1 1 0 0 B
9-6
PLfM-86 User's Guide Built-In Procedur~ Functions and Variables
ABS is a REAL function that returns the absolute value of a REAL value. It is
activated by a function reference with the form:
A B S ( expression)
where
expression has a REAL value.
I AB S ( expression)
where
expression has an INTEGER value.
In a shift, bits moved off one end of the pattern are lost, and zero bits move into the
pattern from the other end (except in the case of SAR-see below). In a rotate, bits
moved off one end move onto the other end.
ROL and ROR are functions whose type depends on the type of the expression given
as an actual parameter. They are activated by function references with the forms:
R 0 L (pattern, count)
R 0 R (pattern, count)
where
pattern and count are expressions with BYTE, WORD, or DWORD values.
If count has a WORD or DWORD value, all but the 8 low-order bits will be dropped
to produce a BYTE value. If the value of count is 0, no rotation occurs.
The value of pattern is handled as an 8-bit, 16-bit, or 32-bit binary quantity that is
rotated to the left (by ROL) or to the right (by ROR). The type of pattern determines
whether a byte, word, or dword rotate is performed. The number of bit positions by
which it is rotated is specified by count.
9-7
Built-In Procedures, Functions and Variables PLfM-86 User's Guide
SHL and SHR are functions whose type depends on the type of the expression given
as an actual parameter. They are activated by function references with the forms:
5 H L (pattern, count)
5 H R (pattern, count)
where
pattern and count are expressions with BYTE, WORD, or DWORD values.
If count has a WORD or DWORD value, all but the 8 low-order bits will be dropped
to produce a BYTE value. If the value of count is 0, no shift occurs.
The value of pattern may be either a BYTE, WORD, or DWORD value and will not
be converted. If it is a BYTE value, the function will return a BYTE value. If pattern
is a WORD value, the function will return a WORD value; if it is a DWORD value,
the function will return a DWORD value.
The value of pattern is shifted left (by SHL) or right (by SHR), with the bit count
given by count.
A shift operation can force a I-bit out of the pattern. For example:
SHL(1000$0001B,1)
SHR(1000$0001B,1)
If the specified pattern and count do not cause such a "lost information" shift, then
a shift of one bit position has the effect of multiplication by 2 for a left shift, or
division by 2 for a right shift. For example, suppose that VAR is a BYTE variable
with a value of 8. This is represented as 0000$1000. SHL(VAR,l) will return
0001$0000, which represents 16, while SHR(VAR,l) will return 0000$0100, which
represents 4.
SAL and SAR are INTEGER functions. They are activated by function references
with the forms:
5 A L (pattern, count)
5 A R (pattern, count)
where
pattern is an expression with an INTEGER value.
count is an expression with a BYTE, WORD, or DWORD value.
9-8
PLjM-86 User's Guide Built-In Procedures, Functions and Variables
If count has a WORD or DWORD value, all but the 8 low-order bits will be dropped
to produce a BYTE value. If the value of count is 0, no shift occurs.
SAL and SAR treat the INTEGER value of pattern as a bit pattern. This pattern is
shifted to the left or to the right.
In a left shift (SAL), O-bits move into the pattern from the right (as in SHL and
SHR).
In a right shift (SAR), either zero bits or one bits move into the pattern from the
left. If the original value of pattern is positive, the sign bit (leftmost bit) is a 0, and
zero bits move in from the left. If the original value is negative, the sign bit is aI,
and one bits move in from the left.
This means, in some instances, that just as with the logical shifts, an algebraic shift
of one bit position can have the effect of multiplication by 2 for a left shift or division
by 2 for a right shift. For example, suppose that VAL is an INTEGER variable with
a value of -8. This value is represented as IIII$IIII$IIII$IOOOB. SAL(VAL,I)
will return IIII $1111 $1111 $OOOOB, which represents - 16, while SAR( VAL, I) will
return IIII$IIII$IIII$IIOOB, which represents -4.
Considered more broadly, a string is any contiguously stored set of BYTE values or
WORD values. We can regard a string as if it were a BYTE or WORD array, and
refer to the BYTE or WORD values as "elements."
We will use the word "index" to refer to the position of a given element within a
string. The index is like the subscript of an array reference. Thus, the index of the
first element of a string is 0, the index of the second element is I, etc.
In the following descriptions, the "location" of a string always means the location of
its first element. In each string-manipulation procedure, the location of a string is
specified by a parameter called "source" or "destination," which is an expression
with a POINTER value. Thus, the source points to the lowest element. For MOVB
and MOVW, this is the first element to be processed. For MOVRB and MOVR W,
it is the last element to be processed, as discussed below.
NOTE
If the source or destination string address is in SELECTOR or WORD form,
use the @ operator of a variable based on the address. Otherwise, the built-in
function BUILD$PTR can be used to construct the pointer-parameter for
the string built-in.
9-9
Built-In Procedur~ Functions and Variables PL/M-86 User's Guide
MOVB is an untyped procedure that copies a BYTE string from one location to
another. It is activated by a CALL statement with the form:
where
source and destination are expressions with POINTER values.
count is an expression with a BYTE or WORD value.
The string elements are copied in ascending order-that is, element 0 is copied first,
then element 1, etc. This is significant if the source string and the destination string
overlap. If the value of destination is higher than the value of source, and the two
strings overlap, elements in the overlap area will be overwritten before they are copied.
This can be avoided by using MOVRB instead of MOVB.
MOVW is the same as MOVB except that it copies a WORD string instead of a
BYTE string.
MOVRB is the same as MOVB except that the elements in the source string are
copied to the destination string in descending order. This is significant when the two
strings overlap. If the value of "destination" is higher than the value of "source," and
an overlap exists, elements in the overlap area will not be overwritten until after they
have been copied. However, if the value of "source" is higher than the value of
"destination," then elements in the overlap area will be overwritten before they are
copied.
MOVRW is the same as MOVRB except that it copies a WORD string instead of a
BYTE string.
NOTE
If two strings overlap, a procedure such as the following can be used to make
the correct choice between MOVB and MOVRB, so that elements in the
overlap area will not be overwritten until after they have been copied.
MOVBYTES: PROCEDURE (SRC, DST, CNT) j
DECLARE (SRC, OST) POINTER, CNT WORDj
IF SRC ) OST THEN CALL MOVB (SRC, OST, CNT)j
ELSE CALL MOVRB (SRC, OST, CNT)j
END MOVBYTESj
This procedure can be activated without the need to consider whether overlap may
occur or whether source or destination is higher.
where
source1 and source2 are expressions with POINTER values.
9-10
PL/M-86 User's Guide Built-In Procedures, Functions and Variables
CMPB compares two BYTE strings of length countwhose locations are source1 and
source2.
If every element in the string at source1 is equal to the corresponding element in the
string at source2, CMPB returns a WORD value of OFFFFH. Otherwise, it returns
the index (position within the strings) of the first pair of elements found to be unequal.
CMPW is the same as CMPB except that it compares two WORD strings instead of
two BYTE strings.
FINDB is a WORD function that searches a BYTE string to find an element that
has a specified value. It is activated by a function reference of the form:
where
source is an expression with a POINTER value.
target is an expression with a BYTE or WORD value. If target has
a WORD value, the 8 high-order bits will be dropped to
produce a BYTE value.
count is an expression with a WORD value.
FINDB examines each element of the source string (in ascending order) until it finds
an element whose value is equal to the BYTE value of target-or until count elements
have been searched without any of them matching target. If the search is successful,
FINDB returns the index of the first element of the string that matches target. If the
search is unsuccessful, FINDB returns a WORD value of OFFFFH.
FINDW is the same as FINDB except that it searches a WORD string instead of a
BYTE string. If the target parameter has a BYTE value, it is extended by 8 high-
order zero bits to produce a WORD value.
FINDRB is the same as FINDB except that it searches the source string in descending
order. Thus, if the search is successful, FINDRB returns the index of the last (highest
subscript) element that matches the BYTE value of target.
FINDRW is the same as FINDRB except that it searches a WORD string instead
of a BYTE string (in descending order).
SKIPB is the "converse" of FINDB (see above). Instead of searching for the first
element in the BYTE source string that matches the BYTE value of target, SKIPB
searches for the first element that does not match.
SKIPW is the "converse" of FINDW (see above). Instead of searching for the first
element in the WORD source string that matches the WORD value of target, SKIPW
searches for the first element that does not match.
9-11
Built-In Procedures, Functions and Variables PLfM-86 User's Guide
SKIPRB is the "converse" of FINDRB (see above). Instead of searching for the last
element in the BYTE source string that matches the BYTE value of target, SKIPRB
searches for the last element that does not match.
SKIPR W is the "converse" of FINDR W (see above). Instead of searchirig for the
last element in the WORD source string that matches the WORD value of target,
SKIPR W searches for the last element that does not match.
where
source, destination, and table are expressions with POINTER values.
count is an expression with a WORD value.
XLAT "translates" the BYTE elements in the source string, placing the translated
elements in the destination string. The value of table is assumed to be the location of
a BYTE string of up to 256 elements. This string is used as a translation table.
The value of an element in the source string is used as an index for the translation
table. The index selects one" element from the translation table; this element is then
copied into the destination string.
For example, if the fifth element in the source string is 202, then 202 is used as an
index for the translation table. The 203rd element of the table is copied into the fifth
. position in the destination string.
The elements of the source string are translated into the destination string in
ascending order.
SETB is an untyped procedure that sets each element of a BYTE string to a single
specified value. It is activated by a CALL statement with the form:
where
newvalue is an expression with a BYTE or WORD value. If it has a
WORD value, the 8 high-order bits are dropped to produce
a BYTE value.
destination is an expression with a POINTER value.
count is an expression with a BYTE or WORD value.
SETB assigns the BYTE value of newvalue to each element of a BYTE string.
9-12
PL/M-86 User's Guide Built-In Procedures, Functions and Variables
SETW is the same as SETB except that it assigns a single WORD value to each
element of a WORD string instead of a BYTE string.
If newvalue has a BYTE value, it will be extended by 8 high-order zero bits to produce
a WORD value.
The values of source and destination are assumed to be the WORD-type addresses of
the source string and the destination string. The operation differs from MOVB as
follows:
• All three parameters must have either BYTE or WORD values, and will be
converted to WORD values if they are BYTE values. POINTER values for source
and destination are not allowed and therefore the values cannot be supplied by
means of the @ operator. Thus, MOVE can only handle strings whose locations
can be expressed as WORD addresses.
• Note that the parameters are in a different order than the one used by the other
built-in string functions.
• If the source and destination strings overlap, the results are always undefined.
The untyped procedure TIME causes a time delay specified by its actual parameter.
It is activated by a CALL statement with the form:
DO I • 1 TO 40;
CALL TIME (250);
EHD;
9-13
Built-In Procedures, Functions and Variables PLfM-86 User's Guide
The TIME procedure is based on iAPX 86 CPU cycle times, and assumes that the
system is running at 5 MHz (8 MHz for the iAPX 186) without interruptions.
A reference to MEMORY may not be used as an actual parameter for the LENGTH,
LAST, and SIZE procedures. However, some systems provide service routines you
can use to learn the size of free memory.
L 0 CK 5 E T ( lockptr, newvalue)
where
lockptr is an expression with a POINTER value.
newvalue is an expression with a BYTE or WORD value. If newvalue
has a WORD value, the 8 high-order bits will be dropped to
produce a BYTE value.
To see how this facility can be used, consider a system having more than one
iAPX 86 processor using the same memory, and consider a program in one of these
processors. Suppose that this program uses memory locations that are also used by
other processors in the system.
Within certain "critical" regions of our program, we want to ensure that no other
processor will access the shared memory locations. To achieve this, we declare a BYTE
variable called LOCK and establish a convention that if LOCK =0, any processor in
the system may access the shared memory locations. But if LOCK = 1, no processor
may access the shared memory locations unless it was the one that set LOCK to 1.
But, if LOCKSET returns a value of 1, then LOCK was already set and this proces-
sor was not the one that set it. By convention, we must wait until a
LOCKSET( @LOCK, 1) function reference returns a value of 0 before assessing the
shared memory locations.
9-14
PL/M-86 User's Guide Built-In Procedur~ Functions and Variables
DO WHILE LOCKSETC,LOCK,11;
If Do nothing but repeat until LOCK SET returns Ofl
ENDj
LOCK-O;
IIEnd critical regionfl
In the simplest case just described, only one software lock is used. It is represented
by the variable LOCK. But, if more than one set of memory locations needed protec-
tion at different times, we could establish as many different software locks as neces-
sary, with each lock using a different BYTE variable.
Also, note that a software lock can be used for other purposes than protecting memory
locations. LOCKSET provides a mechanism that can be used to implement various
types of synchronization in a multiprocessor system.
where name is the interrupt procedure name, and constant is an interrupt number,
i.e., a whole-number constant between 0 and 255.
This built-in function returns the interrupt entry point. Its form is:
9-15
Built-In Procedures. Functions and Variables PLfM-86 User's Guide
The interrupt entry point is not accessible without using this function, since the @
operator refers to the procedure entry point instead. These differences are discussed
in greater detail in Appendix G.
B U I L D • P T R (base, offset)
where
base is an expression with a SELECTOR value.
offset is an expression with a WORD value.
where
pointer is an expression with a POINTER value.
where
pointer is an expression with a POINTER value.
NIL is a POINTER function that returns a pointer with all bytes set to zero. It is
activated by a function reference with the form:
NIL
The pointer value NIL points to no object at all. You may assign the value NIL to a
pointer to indicate, for instance, the end of a linked list.
9-16
PLfM-86 User's Guide Built-In Procedures, Factions and Variables
Note that pointer values generated with the NIL function cannot be used to derefer-
ence data values. For example, if your program contains the following statements:
DECLARE P POINTER;
DECLARE B BASED P BYTE;
P - NIL;
then any subsequent references to B are invalid and will cause a trap.
NOTE
Usage of the NIL pointer can lead to undesirable results.
In the SMALL case, a NIL pointer is defined to be DS:O, which is not distin-
guishable from a valid pointer to the first variable in the data segment (DS).
For example:
$SMALL
M:DO;
DECLARE P POINTER INITIAL (,P);
DECLARE B BYTE;
B - (P-NIL); 1* will assign TRUE (OFFH) to B *1
END;
In all other cases, the NIL pointer is defined to be 0:0, which is not distin-
guishable from a valid pointer to a variable located at absolute address O.
For example:
$LARGE
M:DO;
DECLARE Q BYTE AT (0);
DECLARE B BYTE;
B - (,Q-NIL); 1* will assign TRUE (OFFH) to B*I
END;
9-17
CHAPTER 10
PL/M-86 FEATURES INVOLVING
iAPX 86 HARDWARE
The PL/M-86 features described in this chapter make use, directly or indirectly, of
the iAPX 86 hardware.
These two statements enable and disable the iAPX 86 interrupt mechanism. They
have the forms
ENABLE;
DISABLE;
ENABLE generates an STI instruction, causing the iAPX 86 to enable interrupts.
DISABLE generates a CLI instruction, causing the iAPX 86 to disable interrupts.
where
constant is a whole-number constant in the range 0 to 255.
HALT;
It generates an STI instruction followed by an HLT instruction, causing the iAPX
86 to come to a halt with interrupts enabled (see section 8.5).
10-1
PL/M-86 Features Involving iAPX 86 Hardware PL/M-86 User's Guide
Consequently, the state of the iAPX 86 hardware flags cannot be predicted for any
given point in the program. For example, suppose that a source program contains the
following fragment:
where
SUM is a BYTE variable.
Now, if the value of SUM before this assignment statement is greater than 5, the
addition will cause an overflow and the hardware CARRY flag will be set.
If there were no optimization of the machine code, one could follow this assignment
statement with one of the PL/M-86 features described in the following sections and
be sure that the feature would operate in a certain fashion depending on whether or
not the addition caused the CARRY flag to be set. However, because of the optimi-
zation, some machine code instructions may, occur immediately after the addition and
change the CARRY flag. One cannot safely predict whether this will happen or not.
Accordingly, any PL/M-86 feature that is dependent on the CARRY flag (or any of
the other hardware flags) may cause the program to run incorrectly. These features
must therefore be used with caution, and any program that uses them must be checked
carefully to make sure that it operates correctly.
These four built-in BYTE functions return the logical values of the iAPX 86 hardware
flags. These functions take no parameters, and are activated by function references
with the following forms
CARRY
ZERO
SIGH
PARITY
An occurrence of one of these activations (in an expression) generates a test of the
corresponding condition flag. If the flag is set ( = 1), a value of OFFH is returned. If
the flag is clear ( = 0), a value of 0 is returned.
PLUS and MINUS perform similar to + and -, and have the sam~ precedence.
However, they take into account the current setting of the iAPX 86 CPU hardware
CARRY flag in performing the operation.
10-2
PL/M-86 User's Gtdde PLJM-86 Features Involving iAPX 86 Hardware
Carry-Rotation Functions
SCL and SCR are rotation functions whose type depends on the type of the expres-
sion given as an actual parameter. They are activated by function references with the
forms:
S C L (pattern, count> ;
S CR (pattern, count> i
where
pattern and count are expressions with BYTE or WORD values.
If count has a WORD value, all but the 8 low-order bits will be dropped to produce
a BYTE value. If the value of count is 0, no shift occurs.
The value of pattern is handled as an 8-bit or 16-bit binary quantity that is rotated to
the left (by SCL) or to the right (by SCR), similar to the ROL and ROR functions
described in Chapter 9. The type of pattern determines whether a byte or word rotate
is performed. The number of bit positions by which it is rotated is specified by count.
The bit rotated off one end of pattern is rotated into the CARRY flag, and the old
value of CARRY is rotated to the other end of pattern. In effect, SCL and SCR
perform 9-bit rotations on 8-bit values and 17-bit rotations on 16-bit values.
DEC is a BYTE function that uses the value of the hardware CARRY flag
internally. It is activated by a function reference with the form:
DEC ( expression) ;
where
expression is converted, if necessary, to a BYTE value.
The procedure performs a decimal adjust operation on the actual parameter value
and returns the result of this operation.
The FLAGS register is assigned to change the setting of the various flags. It can also
be read to determine the current flag settings.
Note that the IOPL and IF flags can only be altered when you are executing in
protection mode at level o.
10-3
PLfM-86 Features Involving iAPX Hardware PL/M-86 User's Guide
Ix 'OFIDFIIFITFISFIZFlxIAFlx IPFlxlCFI
I ~L CARRY FLAG
L - (RESERVED)
PARITY FLAG
(RESERVED)
' - - - - - - - - AUXILIARY CARRY FLAG
' - - - - - - - - - - (RESERVED)
' - - - - - - - - - - - ZERO FLAG
' - - - - - - - - - - - - - SIGN FLAG
L -_ _ _ _ _ _ _ _ _ _ _ _ _ SINGLE-STEP TRAP FLAG
STACKPTR and STACKBASE are WORD variables. They provide access to the
iAPX 86 hardware stack pointer and stack base registers, i.e., SP and SS.
When setting these registers (that is, using STACKPTR or STACKBASE on the left
side of an assignment), care must be exercised because this action removes control of
the stack from the compiler. Thus, the compile-time checks on stack overflow and
the compiler's assumptions about the run-time status of the stack may be invalid.
INPUT is a BYTE function and IN WORD is a WORD function. They are activated
by function references with the forms:
I HPUT ( expression)
I HW0 RD (expression)
where
expression has a BYTE or WORD value.
The value of expression specifies one of the input ports of the iAPX 86 CPU. The
value returned by INPUT is the BYTE quantity found in the specified input port.
The value returned by INWORD is the WORD quantity found in the specified input
port.
10-4
PLfM-86 User's Guide PLfM-86 Features Involving iAPX Hardware
OUTPUT is a BYTE array and OUTWORD is a WORD array. Each array has
65536 elements, corresponding to the number of output ports on the iAPX 86 CPU.
where
port and count are expressions with WORD values.
destination is an expression with a POINTER value.
The value of port specifies one of the input ports of the iAPX 86 CPU. The value of
count specifies the length of the BYTE or WORD string found in the specified port,
and destination is the location (in memory) where this string is to be stored.
where
port and count are expressions with WORD values.
source is an expression with a POINTER value.
The value of port specifies one of the output ports of the iAPX 86 CPU. The value
of count specifies the length of the BYTE or WORD string output to the specified
port, and source is the location (in memory) where this string is currently stored.
10-5
PL/M-86 Features Involving iAPX Hardware PL/M-86 User's Guide
;~ M_~ommE ~~ ~CTIYE~~O+
4.
121945-4
o
10-6
PLjM-86 User's Guide PLjM-86 Features Involving iAPX Hardware
7 o
I I I I I
PE UE OE ZE DE liE I EXCEPTION FLAGS (1 = EXCEPTION HAS OCCURRED)
I~
INVALID OPERATION
DENORIIALIZED OPERAND
ZERODIVIDE
OVERFLOW
UNDERFLOW
PRECISION
' - - - - - - - - - - - - - - (RESERVED)
.......- - - - - - - - - - - - - - INTERRUPT REQUEST
15 7 0
~=~~~~I~~~I~=R~C=~~=p~C=~I-E~M-I~~.I-p~M~1~~~1~~~1~~~1~~~1~~~1~~~~~(1=~~~~~~
I II L ~~~RA~
DENORMALIZED OPERAND
ZERODIVIDE
OVERFLOW
UNDERFLOW
PRECISION
L..-_ _ _ _ _ _ _ _ _ _ _ _ (RESERVED)
L......_ _ _ _ _ _ _ _ _ _ _ _ _ _ INTERRUPT.ENABLE MASK(1J(lEM)
' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (RESERVED)
The full extent of the 8087's numeric and operational capabilities are discussed in
the 8086 Family User's Manual Supplement for the 8087 Numeric Data Processor.
10-7
PL/M-86 Features Involving iAPX Hardware PL/M-86 User's Guide
CALL IHIT$REALSMATHSUHIT;
This call is required as the first access to the REAL math facility (the 8087 Numeric
Data Extension).
The effect of this call is to initialize the REAL math unit for subsequent operations.
This includes setting a default value into the control word, namely 03FFH or
0000001111111111 in binary. The effect of this setting is to mask all exceptions and
interrupts, to set precision to 64 bits, and to cause rounding to even. This means no
interrupts will occur from the REAL Math Facility regardless of what errors are
detected.
Procedures activated after this call has taken effect do not need to do such
initialization.
This procedure should only be invoked if you wish to change the default mode word
(for example, to unmask the invalid exception).
where
modeword is an expression with a WORD value.
The value of modeword becomes the new contents of the REAL mode word (see
figure 10-3). The suggested value for modeword is 033EH, that is, 0000001100111110
in binary. This value provides maximum precision, default rounding, and masked
handling of all exception conditions except invalid, which can alert you to errors of
initialization or stack usage. See Appendix G for facts and references on writing an
interrupt handling procedure.
GET$REALSERROR
The BYTE value returned is the current contents of the REAL error byte (see figure
10-1). This function also clears the error byte in the REAL math facility.
10-8
PL/M-86 User's Guide PL/M-86 Features Involring iAPX Hardware
New vectors will be required for the interrupt handlers appropriate to each new task,
e.g., to handle unmasked exception conditions. These vectors must be initialized by
the operating system.
After its processing is complete and it is ready to terminate, the preempting task must
call RESTORE$REAL$STATUS to reload the state information that applied at the
time the former running task was preempted. This enables that' task to resume
execution from the point where it relinquished control.
NOTE
REAL functions without REAL parameters should not call
GET$REAL$ERRORS or SAVE$REAL$STATUS before executing at
least one floating-point instruction. To do so may result in loss of processor
synchronization.
The REAL status is saved at the specified location, and the REAL stack and error
byte are reinitialized.
If the state of the REAL math unit is unknown to this procedure when it is called,
as in the case mentioned above for preempting tasks, then you do not want to do an
initialization because that will destroy existing error flags, masks, and control settings.
The action appropriate to these circumstances (except for error-recovery routines,
discussed in Appendix G) is to issue:
10-9
PL/M-86 Features Involving iAPX Hardware PL/M-86 User's Guide
prior to the procedure's return. The save automatically reinitializes the math unit and
the error byte.
This protects the status of preempted tasks or prior procedures and establishes a known
initialization state for the current procedure's actions. iAPX 86 interrupts are disabled
during the save.
[¥~I
The iAPX 86 processor must be able to acknowledge 8087 interrupts or loss
of synchronization will occur.
where
location is a pointer to a memory area where the REAL status infor-
mation was previously saved by a call to the
SAVE$REAL$STATUS procedure.
This procedure should be called prior to returning from an interrupt procedure where
the real math unit's status was saved using SAVE$REAL$STATUS.
10-10
·1~_ ______________________ __1_1~
COMPILERC_H_A_P_TE_R
CONTROLS
A control line is a source line containing a dollar sign ($) in the left margin. Normally,
the left margin is set at column one, but this may be changed with the LEFTMARGIN
control. Control lines are introduced into the source to allow selective control over
sections of the program. For example, it may be desirable to suppress the listing for
certain sections of the program, or to cause page ejects at certain places.
A line is considered a control line by the compiler if there is a dollar sign in the left
margin, even if it appears to be part of a PL/M-86 comment or character string
constant.
On a control line, the dollar sign is followed by a sequence of controls. These controls
must be separated from each other by one or more blanks.
$MOCODE XREF
$ EJECT CODE
There are two types of controls: primary and general. Primary controls must occur
either in the invocation command or in a control line which precedes the first noncon-
trol line of the source file. Primary controls may not be changed within a module.
General controls may occur either in the invocation command or on a control line
located anywhere in the source input, and may be changed freely within a module.
A large number of controls are available, but you may only need to specify a few of
them for most compilations because a set of defaults is built into the compiler. The
controls are summarized in alphabetic order in table II-I.
LIS T
NOXREF
DBJECTCPROG2.0JB)
Table 11-2 lists the controls in the order in which they are discussed in this chapter,
which is approximately in order of importance or usage. Primary controls have an
asterisk attached. Sample invocation lines for most compiler controls are provided on
a foldout page in your specific operating-system appendix.
11-1
Compiler Controls PL/M-86 User's Guide
MOD8S
MOD18S
Default: MOD 8 S
The MOD86 control specifies that the object module will contain instructions for
execution on the iAPX-86 processor.
The MOD186 control allows the compiler to generate an extended set of instructions
in the object module for use on the iAPX-186 processor.
where
column is a non-zero, unsigned integer specifying the left margin of
the source input.
11-2
PLfM-86 User's Guide Compiler Controls
All characters to the left of this position on subsequent input lines are not processed
by the compiler (but do appear on the listing). The first character on a line is in
column 1.
The new setting of the left margin takes effect on the next input line. It remains in
effect for all input from the source file and any INCLUDE files until it is reset by
another LEFTMARGIN control.
Note that a control line is one that contains a dollar sign in the column specified by
the- most recent LEFTMARGIN control.
INTVECTOR/NOINTVECTOR
OVERFLOW /NOOVERFLOW
OPTIMIZE
OBJECT /NOOBJECT
DEBUG/NQDEBUG
TYPE/NOTYPE
Program Size Controls
RAM/ROM
11-3
Compiler Controls PL/M-86 User's Guide
INTVECTOR/NOtNTVECTOR
IHTVECTOR
HOIHTVECTOR
Default: I HTV ECTOR
Under the INTVECTOR control, the compiler creates an interrupt vector consisting
of a 4-byte entry for each interrupt procedure in the module. For Interrupt n, the
inten:upt vector entry is located at absolute location 4* n. See Chapter 8 and Appen-
dix G for further discussion.
OVERFLOW I NOOVERFLOW
OVERFLOW
HOOVERFLOW
Default: H0 0 VERFLO W
If this control is nested within a program statement, overflow detection will begin
when the next complete statement is evaluated.
Note that the use of the OVERFLOW control results in some expansion of the object
code.
OPTIMIZE
where
n may be 0, 1,2, or 3.
11-4
PLfM-86 User's Guide Compiler Controls
OPTIMIZE(O) is the only level of optimization that does not optimize code
between program lines. Thus, it is the only one that gives guaranteed results
when your programs are debugged with a debugger such as the ICE 86
debugger.
OPTIMIZE(O)
OPTIMIZE(O)specifies only '~folding" of constant expressions.
A • 6 + 3 + A;
OPTIMIZE(l)
OPTIMIZE( 1) specifies strength reduction, elimination of common subexpressions,
short-circuit evaluation of some Boolean expressions, and the above optimizations of
level (0).
A • B + C*D/3;
C • E + D*C/3;
The value of C*D/3 will not be recomputed for the second statement.
Optimizing the evaluation of Boolean expressions uses the fact that in certain cases
some of the terms are not needed to determine the value of the expression. For
example, in the expression:
( A ) B AHD I ) J )
if the first term (A> B) is false, the entire expression is false, and it is not necessary
to evaluate the second term. The use of PL/M-86 built-in procedures does not change
this optimization. However, if a user-function or an embedded assignment is part of
the expression, this short evaluation is not done. For example:
11-5
Compiler Controls PL/M-86 User's Guide
OPTIMIZE(2)
OPTIMIZE(2) specifies all of the above, plus the following:
• Machine code optimizations (e.g., short jumps, moves)
• Elimination of superfluous branches
• Re-use of duplicate code
• Removal of unreachable code and reversal of branch-condition
Optimizing machine code means saving space by using shorter forms for identical
machine instructions. This is possible because the iAPX 86 has multiple forms for
some of its instructions. For example:
LAB2:
will be transformed into:
LAB2:
Similarly, multiple branches like the following are eliminated:
lAB2:
and transformed into:
lAB2:
11-6
PL/M-86 User's Guide CompHer Controls
Reuse of duplicate code can refer to identical code at the end of two converging
paths. In such a case, the code is inserted in only one path, and a jump to that path
is inserted in the other path. For example:
Before After
Reuse of duplicate code can also refer to machine instructions immediately preceding
a loop-instructions that are identical to those ending the loop. A branch can be
generated to re-use the code generated at the beginning of the loop. For example:
Before After
This is safe so long as LABO is not the target of a jump instruction. The compiler
normally handles a whole procedure at a time, and is thus aware of such a condition.
The optimization cannot be safely applied to labels in the outer level of the main
program module. This optimization will not change your program and will save code
space.
The optimization that removes unreachable code takes a second look at the generated
object code and finds areas which can never be reached due to the control structures
created earlier.
11-7
Compiler Controls PLfM-86 User's Guide
MOV AX , A
RCR AL , 1
JB ,1
JMP ,2
, 1: MOV AX , OFFFFH
OUTW OF6H
JMP ,2
MOV AX , B
ADD A, AX
JMP ,3
,2:
,3 : ......
. . . . ..
then the removal of unreachable code would produce:
MOV AX, A
RCR AL,1
JB
JMP
,1,2
,1: MOV AX, OFFFFH
OUTW OF6H
JMP ,2
,2 :
,3 :
This can be further optimized by reversing the branch condition in the third
instruction and removing the unnecessary JMP @2:
MOV AX, A
RCR AL, 1
JHB ,2
,1: MOV AX, OFFFFH
OUTW OF6H
,2:
,3 :
OPTIMIZE(3)
OPTIMIZE(3) includes all of the above optimizations. It also optimizes indetermi-
nate storage operations (e.g., those using based variables or variables declared with
the AT attribute). The assumption validating this new optimization is that based
variables (or AT variables) are not overlaying other user-declared variables.
On this optimization level, all Boolean expressions are short-circuited except those
containing embedded assignments. (For a description of how this optimization occurs,
see OPTIMIZE(1 ).)
11-8
Compiler Controls
The benefits of this optimization level include more efficient use of code space because
the user guarantees that needed values are not overlaid.
J •• I ;
A(I).F1 • 7;
A(I).F2 • 99;
THETA(I) • 31;
violates this caution and guarantee because it causes the values being used as pointers
and subscripts to be overlaid. The compiler normally takes steps to avoid the diffi-
culties implied here. But, in OPTIMIZE(3), these steps are omitted due to the implicit
user guarantee that such situations have been avoided.
Figures 11-1 through 11-4 illustrate the levels of optimization described above.
11-9
Compiler Controls PL/M-86 User's Guide
; STATEMENT # 4
0024 C406CE00 LES AX,PTR- 1
0028 06 PUSH ES ; 1
0029 C416D200 LES DX,PTR_2
002D 8CC7 MOV DI,ES
002F 5E POP SI 1
0030 B104 MOV CL,4H
0032 8BD8 MOV BX,AX
0034 D3EB SHR BX,CL
0036 03F3 ADD SI,BX
0038 8BDA MOV BX,DX
003A D3EB SHR BX,CL
003C 03FB ADD DI,BX
003E 3BF7 CMP SI,D!
0040 7507 JNZ $+9H
0042 240F AND AL,0FH
0044 80E20F AND DL,0FH
oIr:J 47 3AC2 CMP AL,DL
0049 7403 JZ $+5H
004B E94100 JMP @3
STATEMENT it 6
004E 8B1360000 MOV AX,A
0052 D1E0 SHL AX,l
01r:J54 891360000 MOV A,AX
STATEMENT it 7
0058 8B360200 MOV SI,B
005C D1E6 SHL SI,l
005E 8B3E00013 MOV DI,A
0062 D1E7 SHL DI,l
0064 C41ECE00 LES BX,PTR_1
0068 268B00 MOV AX,ES: [BX] .ABASED[SI]
006B C41ECE00 LES BX,PTR 1
006F 268901 MOV ES:[BXT.ABASED[DI],AX
; STATEMENT it 8
0072 8B360400 MOV SI,C
0076 D1E6 SHL SI,l
0078 8B3E0200 MOV 01,8
0!67C D1E7 SHL 01,1
007E C41ECE00 LES BX,PTR_1
01482 268B00 MOV AX , ES: [BX] • ABAS ED [S I ]
0085 C41ECE00 LES BX,PTR_1
00d9 268901 MOV ES:[BX] .ABASED[DI],AX
; STATEMENT It 10
008C E90900 JMP @4
@3:
1608F 8B0ti0000 MOV AX,A
0093 40 INC AX
ItH694 8906000" MOV A,AX
STATEMENT It 11
@4:
0098 E96dFF JMP @l
@2:
STATEMENT # 12
11-10
PL/M-86 User's Guide Compiler Controls
l-tOOULE INFORMATION:
DICTIONARY SUMMARY:
11-11
Compiler Controls PL/M-86 U ..."s GIiIe
MODULE INFORMATION:
DICTIONARY SUMMARY:
11-12
PL/M-86 User's GaRIe Compiler Contt,ols
11-13
Compiler Controls PL/M-86 User's Guide
S'TATEMENT i 8
I,H'58 8B3604101rJ MOV SI,C
005F D1E6 SHL SI,l
0061 8B3E0200 MOV DI,B
0065 D1E7 SIlL 01,1
01007 C41ECE00 LES BX,PTR 1
0166B 268B00 MOV AX,ES:[BX] .ABASED[SI]
906E 268901 MOV ES:[BX}.ABASED[DI] ,AX
; 'STATEMENT i 10
0071 E890 JMP @1
@3:
0073 FF060000 INC A
STATEMENT i 11
0077 EB8A JMP @1
@2:
STATEMENT i 12
MODULE INFORMATION:
11-14
PL/M-86 User's Guide Compiler Controls
STATEMENT # 3
fHJ00 8BEC MOV BP,SP
0002 FB STI
@1:
13003 8B1E001313 MOV BX,A
01307 A102130 MOV AX,B
01613A 0308 ADD BX,AX
0130C 01E3 SHL BX,l
0130E 8B8F06130 MOV CX,D[BX]
01612 3B8F08130 CMP CX,D[BX+2H]
131316 733D JAE @2
; STATEMEWf # 4
0018 C41ECE1313 LES BX,PTR_1
1301C 8CC6 MOV SI,ES
0i61E 3B36D4013 CMP SI,PTR 2+2H
131622 7504 JNZ $+6H -
01324 3BIED2013 CMP BX,PTR 2
0028 7525 JNZ @3 -
STATEHENT # 6
0162A Al1301313 MOV AX,A
0132D DIE13 SHL AX,l
0162F A300130 MOV A,AX
STATEMENT # 7
13032 8B3E02130 MOV DI,B
01336 D1E7 SHL DI,l
131338 01E13 SHL AX,l
0163A 268B0~ MOV CX,ES: [BX].ABASED[DI]
0030 96 XCHG AX,SI
0163E 268908 MOV ES: [BX] .ABASED [SI] ,CX
; STATEMENT # 8
131341 8B36134130 MOV SI,C
0i645 01E6 SHL SI,l
01347 268B138 MOV CX,ES:[BX] .ABASED[SI]
004A 268909 MOV ES: [BX] .ABASED[DI] ,ex
; STATEMENT # 113
0134D EBB4 JMP @1
@3:
004F FF136130130 INC A
STATEMENT # 11
0053 EBAE JMP @1
@2:
STATEMENT # 12
DICTIONARY SUMHARY:
11-15
Compiler Controls PL/M-86 User's Guide
OBJECT I NOOBJECT
OBJECT
oB J E CT ( pathname)
HOOBJECT
Default: 0 B J E C T ( source-file. 0 B J )
The OBJECT control specifies that an object module is to be created during the
compilation. The pathname is a standard operating system pathname that specifies
the file to receive the object module. If the control is absent or if an OBJECT control
appears without a pathname, the object module is directed to the same file name used
for source input, but with the extension OBJ.
As explained later in this chapter, these sections can be combined in various ways
into "memory segments" for execution, depending on the size of the program
(SMALL, COMPACT, MEDIUM, or LARGE).
Code Section. This section contains the object code generated by the source program.
If either the LARGE control or the ROM control is used, this section also· contains
the information that would otherwise be in the constant section.
In addition, the code section for the main program module contains a "main program
prologue" generated by the compiler. This code precedes the code compiled from the
source program, and sets the CPU up for program execution by initializing-various
registers and enabling interrupts.
Constant Section. This section contains all variables initialized with the DATA
attribute, as well as all REAL constants and all constant lists. If the LARGE or
ROM controls are used, this information is placed in the code section and no constant
section is produced.
Data Section. All variables are allocated space in this section except parameters,
based variables, and variables that are located with an AT attribute, initialized with
the DATA attribute, or local to a REENTRANT procedure.
11-16
PLfM-86 User's Guide Compiler Controls
The exact size of the stack is automatically determined by the compiler except for
possible multiple incarnations of reentrant procedures. The user can override this
computation of stack size and explicitly state the stack requirement during the
relocation process.
NOTE
When using reentrant procedures or interrupt procedures the user must be
careful to allocate a stack section large enough to accommodate all possible
storage required by multiple incarnations of such procedures. The stack size
can be explicitly specified during the relocation and linkage process.
The stack space requirement of each procedure is shown in the listing produced by
the SYMBOLS or XREF control. This information can be used to compute the
additional stack space required for reentrant or interrupt procedures.
Memory Section. This is the area of memory referenced by the built-in PL/M-86
identifier MEMORY. Its maximum allowable size depends on the size control used
in compilation (SMALL, COMPACT, MEDIUM, or LARGE) as explained below.
The compiler generates a memory section of length zero, and it is your responsibility
to specify the actual (run-time) space required during the linkage and relocation
process. The iAPX 86,88 Family Utilities User's Guide can assist you in this.
DEBUG/NODEBUG
These are primary controls. They have the form
DEBUG
NDDEBUG
Default: NOD E BUG
The DEBUG control specifies that the object module is to contain the statement
number and relative address of each source program statement, information about
each local symbol (including based symbols and procedure parameters), and block
information for each procedure. This information may be used later by a debugger
such as the ICE 86 debugger.
OPTIMIZE(O) is the only level of optimization that does not optimize code
between program lines. Thus, it is the only one that gives guaranteed results
when your programs are debugged with a debugger such as the ICE 86.
11-17
Compiler Controls PL/M-86 User's Guide
TYPE I NOTYPE
These are primary controls. They have the form
TYPE
HOTYPE
Default: T YP E
The TYPE control specifies that the object module is to contain information on the
variable types output in symbol records. This information may be used later for type
checking by the iAPX 86 Linker, or by a debugger such as the ICE 86 debugger.
The NOTYPE control specifies that such type definitions are not to be placed in the
object module.
These controls specify the memory size requirements of the program that is to contain
the module being compiled. They affect the operation of the compiler in various ways
and impose certain constraints on the source module being compiled.
These controls also influence how locations are referenced in the compiled program,
which leads to certain programming restrictions for each size control.
Note that for maximum efficiency of the object code, the smallest possible size should
be used for any given program. Also note that all modules of a program must be
compiled with the same size control. These are primary controls. They have the form:
SMALL
COMPACT
MEDIUM
LARGE
Default: SMA LL
NOTE
Usage of the NIL pointer can lead to undesirable results (see section 9.7).
Therefore, the SMALL control may be used if the total size of all code sections does
not exceed 64 K, and the total size of all constant, data, stack, and memory sections
does not exceed 64K.
11-18
PLJM-86 User's Guide Compiler Controls
Since there is only one segment for code, the segment address for this segment (CS
register) is never updated during program execution. Likewise, since there 'is only one
segment for constants, data, stack, and memory sections, the segmen.t address for this
segment (DS and SS registers) is never updated (except when an interrupt occurs, as
explained in Appendix G). Therefore, when any location is referenced, only a 16-bit
offset is calculated and then used in conjunction with the appropriate segment address.
POINTER values are therefore 16-bit values in the SMALL case, and this leads to
the following restrictions.
I. POINTER variables may not be initialized with, or assigned, whole-number
constants, for example:
6. If the built-in function SELECTOR$OF is used, it will always return the value
of the DS register. If BUILD$PTR is used, it will ignore the SELECTOR
expression (see section 9.7).
PLjM-80 Compatibility. The SMALL control is the most likely choice when compil-
ing a program written in PL/M-80. The compiler produces error messages to flag
violations of any of the restrictions or to flag the use of the new reserved keyboards
11-19
Compiler Controls PLfM-86 User's Guide
NOTE
Care must be used with the dot operator under conditions other than SMALL
and RAM.
All code and a few prologue constants are addressed relative to CS. All data except
absolute data (declared with the AT (constant) attribute) are addressed relative to
DS. The stack is addressed relative to SS. ES is not initialized and can change during
execution. References to any location require only a 16-bit offset address against
these segment base addresses.
The sole programming restriction in the COMPACT case is that PUBLIC variables
may not be declared AT an absolute location, for example:
END PROC;
P-,PROC; CALL P; 1* POINTER must be used */
W-.PROC; CALL W; 1* not allowed */
END MOD1;
11-20
PL/M-86 User's Guide Compiler Controls
END LPROC;
P=,LPROC; CALL P; 1* not allowed *1
W=.LPROC; CALL W; 1* WORD must be used*1
The constant, data, stack, and memory sections of all modules are combined and are
allocated space within a single segment.
At any moment during program execution, one segment of code is the "current"
segment, and its segment address is kept in the CS register .. This segment address is
updated whenever a PUBLIC or EXTERNAL procedure is activated, since this may
involve a new code segment.
The segment address for the segment containing constants, data, stack, and memory
sections is kept in the OS register (with an identical copy in the SS register) and is
never changed (except when an interrupt occurs, as explained in Appendix G).
END PROC;
P·,PRDC; CALL P; I*recommended where an indirect
call must be used*1
11-21
Compiler Controls PL/M-86 User's Guide
END LPROCj
P=,LPROCj CALL Pj /*not allowed*/
3. A variable that is absolutely located (by using the AT attribute with a numeric
constant) may not have the PUBLIC attribute. For example:
is not allowed.
Restrictions 1 and 2 arise from the fact that the code segment address may change
during program execution. Restriction 3 is the same as Restriction 3 in the
SMALL case, and arises for the same reason.
A separate segment is used for the data section from each compiled module. Thus
the total space required for data sections may exceed 64K, although the size of any
one data section is limited to 64K.
The stack sections from all modules are combined in one segment, and the memory
sections for all modules are combined in another segment. Thus the total space
required for stack is limited to 64K, and the total space required for memory is also
limited to 64K.
At any moment during program execution, one code segment and one data' segment
are "current." Code and data segments are paired, so that the current code and data
segments are always from the same module. The compiler implements this pairing by
placing the segment address for the data segment in a reserved location in the code
section. During program execution, the segment addresses for the current code and
data segments are kept in the CS and DS registers, respectively, and are updated
whenever a PUBLIC or EXTERNAL procedure is activated, as this may involve new
code and data segments.
11-22
PL/M-86 User's Guide Compiler Controls
Programming Restrictions in the LARGE Case. These first two are the same as
Restrictions 1 and 2 in the MEDIUM case, and arise for the same reason.
1. When a PUBLIC or EXTERNAL procedure is indirectly activated, a POINTER
variable must be used in the CALL statement, for example:
END PROC;
P=,PROC; CALL P; /*recommended where an indirect
call must be made*/
END LPROC;
P=,LPROC; CALL P; /*not allowed*/
RAM/ROM Control
This primary control directs the object-module placement of all constants, both
user-defined and compiler-generated. Its form is:
RAM
ROM
Default: RAM (except in LARGE model)
The default setting places the CONSTANT section within the DATA segment in all
segmentation models (sizes) except LARGE, in which constants are placed in the
CODE segment instead.
The ROM setting places constants in the CODE segment. Under this setting, the
INITIAL attribute on a variable produces a warning message. The dot operator is
not advised for variable references under the ROM option since constants and varia-
bles will be relative to different segment registers. If SMALL is also specified, then
pointers will be four bytes instead of two. (See also Appendix F.)
If the keyword DATA is used in a PUBLIC declaration when compiling with the
ROM control, DATA must also be used in the EXTERNAL declaration of program
modules that reference it. However, no value list is then permitted since the data is
defined elsewhere.
11-23
Compiler Controls PL/M-86 User's Guide
PRINT /NOPRINT
LIST /NOLIST
CODE/NOCODE
XREF /NOXREF
SYMBOLS/NOSYMBOLS
PRINT INOPRINT
P R I HT
P R I HT (pathname)
HOPRIHT
Default: P R I HT (source-file. L S T )
LIST I NOLIST
LIS T
HOLIST
Default: LIS T
The LIST control specifies that listing of the source program is to resume with the
next source line read.
The NOLIST control specifies that listing of the ,source program is to be suppressed
until the next occurrence, if any, of a LIST control.
When LIST is in effect, all input lines (from the source file or from an INCLUDE
file), including control lines, are listed. When NOLIST is in effect, only source lines
associated with error messages are listed.
Note that the LIST control cannot override a NOPRINT control. If NOPRINT is
in effect, no listing whatsoever is produced.
11-24
PLfM-86 User's Guide Compiler Controls
CODE I NOCODE
CODE
HOCODE
Default: HOC 0 DE
The CODE control specifies that listing of the generated object code in standard
assembly language format is to begin. This listing is placed at the end of the program
listing on the listing file.
The NOCODE control specifies that listing of the generated object code is to be
suppressed until the next occurrence, if any, of a CODE control.
XREF/NOXREF
XREF
HOXREF
Default: N0 XREF
The XREF control specifies that a cross-reference listing of source program identi-
fiers is to be produced on the listing file.
SYMBOLS I NOSYMBOLS
SYMBOLS
HOSYMBOLS
Default: H0 S Y MB 0 L S
The SYMBOLS control specifies that a listing of all identifiers in the PL/M-86 source
program and their attributes is to be produced on the listing file.
11-25
Compiler Controls PL/M-86 User's Guide
PAGING/NOPAGING
PAGING
NOPAGING
Default: P AG I HG
The PAGING control specifies that the listed output is to be formatted onto pages.
Each page carries a heading identifying the compiler and a page number, and
possibly a user specified title.
The NOPAGING control specifies that page ejecting, page heading, and page
numbering are not to be performed. Thus, the listing appears on one long ''''page'' as
would be suitable for a slow serial output device. If NOPAGING is specified, a page
eject is not generated if an EJECT control is encountered.
PAGELENGTH
where
length is a non-zero, unsigned integer specifying the maximum
number of lines to be printed per page of listing output. This
number is taken to include the page headings appearing on
the page.
PAGEWIDTH
where
width is a non-zero, unsigned integer specifying the maximum line
width, in characters, to be used for listing output.
The minimum value for width is 60; the maximum value is 132.
11-26
PLfM-86 User's Guide Compiler Controls
TITLE
TIT LE ( , title' )
Default: TIT LE (' module name' )
where
title is a sequence of printable ASCII characters that are enclosed
in quotes.
The sequence, truncated on the right to fit, if necessary, is placed in the title line of
each page of listed output.
The maximum length allowed for title is 60 characters, but a narrow pagewidth may
restrict this number further. For example:
SUBTITLE
where
subtitle is a sequence of printable ASCII characters that are enclosed
in single qUQtes.
The sequence, truncated on the right to fit, if necessary, is placed in the subtitle line
of each page of listed output.
The maximum length allowed for subtitle is 60 characters, but a narrow pagewidth
may restrict this number further. For example:
A subsequent SUBTITLE control causes a page eject, and the new subtitle appears
on the next page and all subsequent pages until the next SUBTITLE control.
EJECT
EJECT
I t causes printing of the current page to terminate and a new page to be started. The
control line containing the EJECT control is the last one printed on the old page.
11-27
Compiler Controls PL/M-86 User's Guide
During the compilation process, a listing of the source input is produced. Each page
of the listing carries a numbered page-header that identifies the compiler, prints a
time and date as designated by the host operating system, and optionally gives a title
and a subtitle, and/or a date (see figure 11-5).
The first part of the listing contains a summary of the compilation, beginning with
the compiler identification and the name of the source module being compiled. The
next line names the file receiving the object code. Then, the command line used to
invoke the compiler is reproduced. The listing of the program itself is shown in figure
11-5.
The listing contains a copy of the source input plus additional information. Two
columns of numbers appear to the left of the source image. The first column provides
a sequential numbering of PL/M-86 statements. Error messages, if any, refer to these
statement numbers. The second column gives the block nesting depth of the current
statement.
Lines included with the INCLUDE control are marked with an equal sign (=) just
to the left of the source image. If the included file contains another INCLUDE control,
lines included by this nested INCLUDE are marked with an "= I". For yet another
level of nesting, "= 2" is used to mark each line, and so forth up to the compiler's
limit of five levels of nesting. These markings make it easy to see where included text
begins and ends.
Should a source line be too long to fit on the page in one line, it will be continued on
the following line. Such continuation lines are marked with a hyphen (-) just to the
left of the source image.
The CODE control may be used to obtain the iAPX 86 assembly code produced in
the translation of each PL/M-86 statement. This code listing appears interspersed in
the source text. in six columns of information in a pseudo-assembly language format:
l. Location counter (hexadecimal notation)
2. Resultant binary code (hexadecimal notation)
3. Label field
4. Opcode mnemonic
5. Symbolic arguments
6. Comment field
Not all six of these columns will appear on anyone line of the code listing. Compiler
generated labels (e.g., those which mark the beginning and ending of a DO WHILE
loop) are preceded by an AT sign (@). The comments appearing on PUSH and POP
instructions indicate the stack depth associated with the stack instruction.
Depending on whether the SYMBOLS or XREF control was used to request the
identifier usage summary, six or seven types of information are provided in the symbol
or cross-reference listing. These are as follows:
1. Statement number where identifier was defined
2. Relative address associated with identifier
11-28
PLfM-86 User's Guide Compiler Controls
STACK: DO;
/* This module implements a BYTE stack with push and pop */
2 1 DECLARE S(100) BYTE, /*Stack Storage*/
T BYTE PUBLIC INITIAL(-1); /*Stack Index*/
11-29
Compiler Controls PL/M-86 User's Guide
Notice that a single identifier may be declared more than once in a source module
(i.e., an identifier defined twice in different blocks). Each such unique object, even
though named by the same identifier, appears as a separate entry in the listing.
The address given for each object is the location of that object relative to the start of
its associated section. The object's attributes determine which section is applicable.
Identifiers in the SYMBOLS or XREF listing are given in alphabetical order with
the following exception: members of structures are listed, in order of declaration,
immediately following the entry for the structure itself. Indentation is used to
differentiate between these entries.
The XREF listing differentiates between items 6 and 7 by adding the character to
statement numbers where a value is assigned. For example, if statement 17 read:
+ 1;
the list of statement numbers would include 17 and 17*, indicating a reference and
an assignment in statement 17.
The AUTOMATIC attribute indicates that the identifier was declared as a parame-
ter or as a local variable in a REENTRANT procedure and therefore is allocated
dynamically on the stack.
4 0004H 1 B.
·· BYTE IN PROC (PUSH) PARAMETER
AUTOMATIC 4 5
PUSH ·
7 001CH 23 POP. PROCEDURE BYTE PUBLIC STACK=0002H
PROCEDURE PUBLIC STACK=0004H
3 0000H 28
·
2
1
0000H
0000H
100 S.
· · .. . . .
STACK.
BYTE ARRAY(100)
PROCEDURE STACK=0000H
5* 8
2 0064H 1 T.
·· BYTE PUBLIC INITIAL
5 5* 8 8*
11-30
PLfM-86 User's Guide Compiler Controls
Compilation Summary
MODULE INFORMATION:
11-31
Compiler Controls PLfM-86 User's Guide
INCLUDE
SAVE/RESTORE
INCLUDE
INCLUDE is a general control, with the form:
I HC L UDE ( pathname)
where
pathname is a standard operating system pathname specifying a file.
The INCLUDE control causes subsequent source lines to be input from the specified
file. Input will continue from this file until an end-of-file is detected. At that time,
input will be resumed from the file which was being processed when the INCLUDE
control was encountered.
An included file may itself contain INCLUDE controls. Note that such nesting of
included files may not exceed a depth of five.
SAVE/RESTORE
These are general controls. They have the form:
SAVE
RESTORE
These controls allow the settings of certain general controls to be saved on a stack
before an INCLUDE control switches the input source to another file, and then
restored after the end of the included file. However, SAVE and RESTORE can be
used for other purposes as well. The controls whose settings are saved and restored
are:
LIST /NOLIST
CODE/NOCODE
OVERFLOW /NOOVERFLOW
LEFTMARGIN
COND/NOCOND
The SAVE control saves all of these settings on a stack. This stack has a maximum
capacity of five sets of control settings, which corresponds to the maximum nesting
depth of five for the INCLUDE control.
The RESTORE control restores the most recently saved set of control settings from
the stack.
11-32
PL/M-86 User's Guide Compiler Controls
IF /ELSEIF /ELSE/ENDIF
SET/RESET
COND/NOCOND
IF IELSE/ELSEIF IENDIF
These controls provide the actual conditional capability using conditions which are
based on the values of switches.
These controls cannot be used in the invocation of the compiler, and each must be
the only control on its control line.
An IF control and an ENDIF control are used to delimit an "IF element," which can
have several different forms. The simplest form of IF element is:
S I F condition
text
SEHDIF
where
condition is a limited form of PL/M expression in which the only
operators allowed are OR, XOR, NOT, AND, <, < =, =,
> =, and >, and the only operands allowed are switches and
whole-number constants in the range 0 to 255. If the switch
did not appear_ in a set control, a value of "false" (0) is
assumed. Parenthesized subexpressions are not allowed.
Within these restrictions, condition is evaluated according to
the PL/M-86 rules for expression evaluation. Note that
condition must be followed by a carriage return.
text is text which will be processed normally by the compiler if
the least significant bit of the value of condition is aI, or
skipped if the bit is a O. Note that text may contain any
mixture of PL/M-86 source and compiler controls. If the text
is skipped, any controls within it are not processed.
$IF condition
text 1
.ELSE.
text 2
.EHDIF
In this construction, text 1 will be processed normally if the least significant bit of
the value of condition is aI, while text 2 will be skipped. If the bit is a 0, text 1 will
be skipped and text 2 will be processed normally.
11-33
Compiler Controls PLfM-86 User's Guide
EXAMPLE: DO;
$IF DEBUG = 1
CALL PRINT$DIAGNOSTICS (TRUE, FALSE);
$ RESET (TRAP)
$ELSEIF DEBUG = 2
CALL PRINT$DIAGNOSTICS (TRUE, TRUE);
$ RESET (TRAP)
$ELSEIF DEBUG = 3
10 1 CALL PRINT$DIAGNOSTICS (TRUE, TRUE);
11 1 CALL PRINT$DIAGNOSTICS (TRUE, TRUE);
$ SET (TRAP)
$ENDIF
$IF TRAP
12 1 CALL DISPLAY$PROMPT;
13 1 CALL AWAIT$CRi
$ENDIF
14 1 END EXAt1PLE;
MODULE INFORMATION:
DICTIONARY SUMMARY:
11-34
PLfM-86 User's Guide Compiler Controls
The most general form of IF element allows one or more ELSEIF elements to be
introduced before the ELSE element (if any):
S I F condition 1
text 1
S E L S ElF condition 2
text 2
S E L S ElF condition 3
text 3
S E L S ElF condition n
textn
SELSE
textn + 1
SENDIF
where any of the ELSEIF elements may be omitted, as may the ELSE element.
The conditions are tested in sequence. As soon as one of them yields a value with a 1
as its least significant bit, the associated text is processed normally. All other text in
the IF element is skipped. If none of the conditions yields a least significant bit of 1,
the text in the ELSE element (if any) is processed normally and all other text in the
IF element is skipped
SET/RESET
These are general controls. The SET control has the general form":
where
switch assignment list consists of one or more switch assignments separated by
commas.
switch
or:
switch = value
where
switch is a name which is formed according to the PL/M-86 rules
for identifiers. Note that a switch name exists only at the
compiler control level, and therefore you may have a switch
with the same name as an identifier in the program; no
conflict is possible. However, note that a PL/M-86 reserved
word may not be used as a switch name.
value is a whole-number constant in the range 0 to 255. This value
is assigned to the switch. If the value and the equal sign ( = )
are omitted from the switch assignment, the default value
OFFH ("true") is assigned to the switch.
11-35
Compiler Controls PL/M-86 User's Guide
$SET(TEST,ITERATIDH=3}
This example sets the switch TEST to "true" (OFFH) and the switch ITERATION
to 3. Note that switches do not need to be declared.
Figure 11-8 is an example of a program that was compiled using the SET control.
CONO/NOCONO
These controls determine whether text within an IF element will appear in the listing
if it is skipped. These general controls have the form:
eOHD
HoeOHD
Default: C 0 HD
The COND control specifies that any text that is skipped is to be listed (without
statement or level numbers). Note that a COND control cannot override a NOLIST
or NOPRINT control, and that a COND control will not be processed if it is within
text which is skipped.
The NOCOND control specifies that text within an IF element which is skipped is
not to be listed. However, the controls that delimit the skipped text will be listed,
providing an indication that something has been skipped. Note that a NOCOND
control will not be processed if it is within text that is skipped.
Figure 11-9 is an example of a program that was compiled using the NOCOND
control.
EXAt1PLE: DO;
11-36
PLJM-86 User's Guide Compiler Controls
$IF DEBUG = 1
$ELSEIF DEBUG = 3
10 1 CALL PRINT$DIAGNOSTICS (TRUE, TRUE) ;
11 1 CALL PRINT$DIAGNOSTICS (TRUE, TRUE) ;
$ SET (TRAP)
$ENDIF
$IF TRAP
12 1 CALL DISPLAY$PROMPTi
13 1 CALL At'lAIT$CR;
$ENDIF
14 1 END EXAMPLE;
MODULE INFORMATION:
11-37
• 8 CHAPTER 12
SAMPLE PROGRAM
In the sample program given in figure 12-1, we first declare a procedure called
SORTPROC which implements the following sorting method (assume that the records
are all in memory, stored as an array of structures). The key for each record is a
member of the structure.
Now we go through the array from the second record (record number 1) upwards.
When we reach any given record (the "current" record), we will already have sorted
the preceding records. (The first time through, when we look at record number 1,
record number 0 is the only preceding record.)
We take the current record, store it temporarily in a buffer, and look backwards
through the preceding records until we find one whose key is not greater than that of
the current record. Then we put the current record just after this record.
This procedure makes only the following assumptions about the records it is to sort:
• Each record occupies a contiguous set of storage locations. Therefore, by using
based variables, each record can be handled as a sequence of bytes, even though
the parts of a record are not necessarily BYTE scalars.
• The records themselves are also stored contiguously, so the entire set of records
can be regarded as a single sequence of bytes. The location of the first byte of
the first record is specified by the POINTER parameter PTR.
• All records are the same size; that is, each occupies the same number of bytes.
This size is specified by the WORD parameter RECSIZE and may not exceed
128.
• In each record, the value of one byte is used as the sort key. Within each record,
this byte is always in the same relative position, that is, the first byte in the
record, or the third, etc. This relative position (or offset) is specified by the
WORD parameter KEYINDEX, which resembles an array subscript; that is, it
is 0 if the key is the first byte in the record, 1 if the key is the second byte, etc.
• The number of records is specified by the WORD parameter COUNT.
After the PROCEDURE statement and the declaration of the parameters, we declare
a based BYTE array called RECORD. This array is based on the parameter PTR,
which points to the beginning of the first record to be sorted. Therefore, a reference
to a scalar element of RECORD will be a reference to some byte within the set of
records to be sorted as long as the subscript used with RECORD is less than the total
number of bytes in all the records (i.e., the subscript must be less than
COUNT * RECSIZE).
Next, we declare CURRENT, an array of 128 BYTE elements; this array will be
used to store the "current" record. Note that the dimension (size) of the array
CURRENT is what establishes the maximum size of the records that this procedure
can handle. We have chosen 128 here, but, in principle, any dimension could be
specified.
12-1
Sample Program PLfM-86 User's Guide
/* Parameters:
PTR is pOinter to first record.
COUNT is number of records to be sorted.
RECSIZE is number of bytes in eacn record, max is 128.
KEYINDEX is byte position witnin each record of a BYTE scalar
to be used as sort key. */
14 2 END SORTPROC;
12-2
PL/M-86 User's Guide Sample Program
MODULE INFORMATION:
The WORD variables I and J are used to control the DO WHILE iterative DO loops.
J is the index variable of the DO statement, and is always the subscript of the current
record. (When J becomes greater than 127, the sort is done.) I is the index variable
used to control the DO WHILE block; I-I is always the subscript of a previously
sorted record. In this program, I and J are also used to calculate subscripts for the
based array RECORD.
In the statement following the iterative DO, we used the built-in procedure MOVB
to copy a sequence of byte values from one storage location to another. (See
Chapter 9 for details.)
To illustrate the way this procedure can be used, it is a set in a program that declares
two sets of records, SET 1 and SET2, and sorts them. Comments are inserted in place
of the code that would be used in a working program to read data into the records
and write it out after they are sorted.
SETI is a set of 50 structures, each of which represents one record. Each structure
contains a WORD scalar, an array of 12 BYTE scalars, an INTEGER scalar, a
REAL scalar, and another BYTE scalar. We want to sort the records using the first
element of the 12-byte array as the sort key. Since the key is the second element
within the structure, its offset is just the number of bytes occupied by the first element
of the structure. Therefore, we will use the built-in function SIZE to calculate the
offset of the key and use that as the value of the parameter KEYINDEX.
12-3
Sample Program PLfM-86 User's Guide
is both error prone and inflexible. If the elements within the structure are changed,
then we must remember to recalculate the offset of the key. A better method is to let
the compiler calculate the offset for us. This can be accomplished by subtracting the
location of the key element from the location of the start of the record. The result of
this subtraction is the offset of the key, which becomes the value of the parameter
KEYINDEX.
In the two CALL statements used to activate SORTPROC, we used the built-in
function LENGTH to determine the number of records that are to be sorted, and we
used the built-in function SIZE to calculate the number of bytes occupied by each
record. These two values are used for the COUNT and RECSIZE parameters for an
activation of SORTPROC. See Chapter 9 for complete details on built-in functions.
NOTE
To generate and output reasonable sort data, user-supplied routines must be
added to this program in the areas indicated.
12-4
CHAPTER 13
PL/M-86 EXTENDED
SEGMENTATION MODELS
13.1 Introduction
Program segmentation is a technique used to optimize the object code produced by
the compiler. It allows for easier, more efficient memory addressing.
The simplest way to compile PLfM-86 code is to use the program size controls
(SMALL, COMPACT, MEDIUM, and LARGE) outlined in Chapter 11. However,
PLfM-86 provides extended segmentation facilities to take full advantage of the
segmented iAPX 86 architecture and to simplify the development of very large
programs. This chapter discusses the segmentation control options available to you.
Each compilation produces an object module composed of several sections (see section
11.4). At link time, the sections from separately compiled modules are combined into
segments depending on compiler-generated attributes and your input to the iAPX 86
Linker. Once combined into a segment, all constituent sections can be addressed from
the same iAPX 86 segment register. The compiler uses this segment addressability to
improve the code produced for data references and procedure calls. The primary
purpose of the segmentation controls is to tell the compiler how separately compiled
code and data will be located in memory.
By making the variety of segmentation schemes open to you virtually unlimited, these
controls can reduce the storage required for pointers and the code required to refer-
ence external variables and procedures.
Extended Segmentation
You can use segment controls to create a large program where each module is
compiled with the same segmentation control, or you can use the extended controls
to partition your program into a number of loosely-coupled subsystems.
Optimized code is obtained by breaking LARGE programs (greater than 64K bytes
of code, data, or both) into COMPACT subsystems having less than 64K bytes of
code and less than 64K bytes of data. References between modules in the same
subsystem can then use more efficient 16-bit addresses. (Only references outside a
subsystem need to use the full 32-bit address.) Use of these extensions also allows
easier access to the 16 megabyte address space.
13-1
PLfM-286 Extended Segmentation Models PL/M-86 User's Guide
13.2 Subsystems
By carefully constructing subsystems, you can minimize references to outside resources
(code and data) and, in return, receive highly optimized code for all internal resource
references. This section describes how to create subsystems using the extended
segmentation controls.
Note that all modules in your program should be compiled with the same set of
subsystem definitions so the compiler will make consistent assumptions about the
location of externals. If inconsistent subsystem definitions are used when compiling
modules, the iAPX 86 Linker (LINK86) will generate an error.
Each subsystem in a PL/M-86 program has one segmentation control, which takes
one of the following forms:
1) $ model ( subsytem-id
\
[submode~ HAS module-list [{ '1; HAS module-list
E XP 0 R T 5 public-list
lJ)
...
where
model specifies the model of segmentation that the subsystem will
follow (COMPACT and LARGE are allowed, but
LARGE subsystems will not provide optimized code). All
modules in the subsystem must be compiled with the same
segmentation model.
HAS module-list specifies all the modules that make up the subsystem. A
HAS list is required by all closed subsystems (see below).
Each identifier in the module-list is the name of a module,
which can be up to 31 characters long.
13-2
P~/M-86 User's Guide PLfM-286 Extend£d Segmentation Models
In most applications of the subsystem controls, the- HAS and EXPORTS lists will
have several dozen entries apiece. To accommOdate lists of this length, a subsystem
control may be continued over more than one control line. (The continuation lines
must be contiguous, and each must begin with a dollar sign ($) in the first column).
Also, note that any number of HAS and EXPORTS lists may appear in a control, in
any order, allowing you to format your subsystem specification so it can be easily
read and maintained.
This sample program contains three subsystems: Room, Diner, and Allocate. Room
and Diner use the COMPACT model of segmentation while Allocate uses the LARGE
model. Constants are stored with the code in Room and Allocate. The Room sub-
system, which contains the modules Chair, Door, and Window, is apparently the main
program because it exports no objects. Allocate supplies four objects: CodeSize,
DataSize, MemSize, and FreeSpace.
The subsystems that make up your PL /M-86 program may be either open or closed.
The subsystem definition for an open subsystem does not have a subsystem name and
does not list the modules it contains; in short, it does not contain a HAS list. Modules
can be added to this subsystem at any time without changing the subsystem
definition. Each program may have only one open subsystem.
The subsystem definition· for a closed subsystem contains a subsystem name and a
HAS list, which specifies all the modules in the subsystem.
In an open subsystem, only the submodel and EXPORTS modifiers are permitted.
By omitting the subsystem name, you automatically create an open subsystem that
contains all modules not claimed in another subsystems's HAS list. (Note that use of
the simple segmentation controls also creates an open subsystem.)
For example, assume that the following modules from your original program
(ATTACH, OPEN, CLOSE, ERRORS, ALLOCATE, FREE) were compiled with
this simple control:
$COMPACT
If you factor out the modules ALLOCATE and FREE from the original program,
creating SUBSYS I, its subsystem definition would be:
13-3
PLfM-286 Extended Segmentation Models PLfM-86 User's Guide
Now, suppose that the modules remaining in the open subsystem reference entry points
AllocBuff and FreeBuff in SUBSYSl. These must be exported from SUBSYSI as
follows:
or
However, because short pointers are used in the SMALL (RAM) model of segmen-
tation, care must be used when you call procedures that have pointer parameters and
are exported from a subsystem. In these cases, the compiler will always use the value
of the current DS register as the selector portion of the long pointer. This means that
passing a pointer to arty data items declared in the SMALL module will produce the
proper result, but the following restrictions must be observed for the special cases:
I. If the actual parameter is the NIL pointer, DS:O will be passed to the exported
procedure. Consequently, the procedure will execute differently if called from a
SMALL module than it will if called from a COMPACT, MEDIUM,.or LARGE
module. For example:
13-4
PL/M-86 User's Guide PL/M-186 Extended Segmentation Models
M: DO;
DECLARE PTR POINTER;
FOO: PROCEDURE (P) EXTERNALj
DECLARE P POINTER;
END FOO;
CALL FOO (NIL); 1* Wrong, will pass DS:O *1
PTR • NIL;
CALL FOO (PTR); 1* Wrong, will pass DS:O *1
END M;
.COMPACT (FOO HAS N; EXPORTS FOO)
H: DO;
FOO: PROCEDURE (P) PUBLIC;
DECLARE P POINTER;
DECLARE B BYTE;
B • (P·NIL); /* Will assign FALSE
(OOOH) to B if FOO i5
called from SMALL;
Will assign TRUE
(OfFH) to B
otherwise *1
END FOO;
CALL FOO (HIL); 1* Right, will pass
o: 0 f I
END Ni
2. If the actual parameter is a pointer to a procedure, the compiler will extend the
short pointer with DS then pass the value of DS:( offset of procedure) to the
exported procedure. This situation should be avoided because the result of any
reference through such a pointer is undefined. For example:
PTR • ,TABLE;
CALL FOO (PTR); '* Right, will pass pointer
to TABLE *'
END M;
Placement of Controls
The segmentation controls have special restrictions associated with their placement.
These rules are as follows:
Only the definition of the open subsystem (with no submodel and no EXPORTS
list) may be placed on the invocation line; definitions of all other subsystems
must occur inside the source program.
• The definition of the open subsystem (if present) must be the last segmentation
control specified.
• Only the open subsystem can be without a HAS list.
The subsystem definitions for your entire program may be included in the compila-
tion of each module using the INCLUDE control. The compiler will extract -the
information' it needs to compile correctly and efficiently each module's intrasub-
system and intersubsystem references.
13-6
CHAPTER
ERROR MESSAGES
141
The source errors are reported in the program listing; the fatal errors are reported on
the console device.
or:
where
mmm is the error number from the list below.
nnn is the source statement number where the error occurs.
ppp is the actual source line number where the error occurs.
aaa is the source text near where the error is detected.
message is the error explanation from the list below.
A prefix of W means the message is a warning only, and object code was not
suppressed. Errors not so prefixed prevent object code generation.
1. IHVALID CONTROL
Primary controls may appear as control lines in your source program, but
they must come first. No other statements may precede them. See
Chapter 11.
14-1
Error Messages PLfM-86 User's Guide
$LIST (MVPROG.LST);
PRINT (:CI:) would be an example, since you cannot print to the console
input device. See Chapter 11.
14-2
PL/M~6 User's Guide Error Messages
For example, if you include a file named A, which includes a file named
B, and so on, this error will arise when the limit is exceeded.
RESTORE can only work if there has been a prior SA VE. See
section 11.7.
14-3
Error Messages PL/M-86 User's Guide
Identifier does not meet the rules for PL/M identifiers. See section 2.3.
Look near the text flagged for an invalid character, or one that IS
inappropriate in context. Delete it or retype the statement.
Match your intended variable type with the length of the flagged item.
For the correct maximum. lengths, see Chapters 2 and 3.
This might reflect missing operators, e.g., A=4T instead of4+T. See
Chapter 2 for the list of v)llid types.
For example, 107B and OABCD will cause this error because neither can
be valid in any PL/M-86 interpretation; 7 is not a binary numeral, B may
not occur in decimal or octal, and neither string ends in H. See Chapter
2.
14-4
PL/M-86 User's Gaitte Error Messages
This error occurs when too many DECLARE statements refer back
through each other to the one that actually supplies a type. For example:
The compiler deleted the following tokens while attempting to recover from
a syntax error.
14-5
Errot Messages PL/M-86 User's Guide
44. C 0 H 5 T A H T TOO l A R GE
See section 6.1. If a label is supplied in an END statement, the label must
match the first unmatched DO statement above the EN D. Sometimes the
error involves a module name confused with a procedure name. See also
Chapters I and 7.
14-6
PL/M-286 User's Guide Error Messages
Star dimension( *) must not be used with structures. See section 3.2.
The flagged item already has a definition declared at this block level.
Each label must be unique within its block or scope. Otherwise, GOTOs
and CALLs would have ambiguous targets. See sections 6.3 and 8.2.
14-7
Error Messages PL/M-S6 User's Guide
A parameter named in the procedure statement did not get defined in the
body of the procedure. See sections 8.1 and 8.2.
You can intersperse declarations and procedures, but not declarations and
executable statements. See Chapter 1.
14-8
PLjM-86 User's Guide Error Messages
Reentrant procedures may not contain nested procedures. See section 8.5.
Procedures must have exactly one name; no more, no less. See section 8.1.
82. S I Z E E X CE E D S 6 .. K 'B Y T E S
14-9
Error Messages PLjM-86 User's Guide
A variable may not be declared using both the DATA attribute and the
A T attribute. See section 3.2.
Variables declared with INITIAL are not initialized until load-time. Thus,
if your program is burned into ROM, these initializations will never occur.
See section 3.2.
The program has too many complex expressions, cases, etc. Break it into
smaller procedures.
The program has too many complex expressions, cases, etc. Break it into
smaller procedures.
The program has too many complex expressions, cases, and procedures.
Break it into smaller modules.
The program has too many nested DO blocks. Break it into smaller
procedures.
14-10
PL/M-86 User's Guide Error Messages
The statement is too large for the compiler. Break it into several smaller
statements.
105. HOT A S T RU CT UR E
For example, a reference of the form GNU.F], where GNU was not
declared a structure. See Chapter 5.
] 07. U ND E FIN E D ME MB E R
14-11
Error Messages PL/M-86 User's Guide
The identifier following GOTO must be a label~ the flagged item was
declared otherwise.
An untyped procedure does not return a value; thus, its RETURN state-
ment may not specify one. See section 8.2.
Only WORD or POINTER scalars can be used for indirect calls. This
excludes WORD or POINTER expressions, BYTE, DWORD,
INTEGER, or REAL scalars, all structures, and all arrays. See
section 8.2.
14-12
PL/M-86 User's Guide Enor Messages
118. T Y P E CON F L I C T
14-13
Error Messages PL/M-86 User's Guide
For example:
Absolute locations for PUBLICs are supported only under the LARGE
option. See Chapter 11.
14-14
PLfM-86 User's Guide Error Messages
14-15
Error Messages PL/M-86 User's Guide
The LENGTH, LAST, and SIZE built-in' functions cannot be used with
variables declared with a star (*) and the EXTERNAL attribute.
The LENGTH, LAST, and SIZE built-in functions cannot be used with
declared with * and the EXTERNAL attribute.
vari~bles
14-16
PL/M-86 User's Guide Error Messages
14-17
Error Messages PLfM-86 User's Guide
The REAL stack has eight registers. Heavily nested use of REAL functions
with REAL expressions as parameters could get excessively complex. See
Appendix F.
You have a very long list of statements without labels, CASEs, IFs,
GOTOs, RETURNs, etc. Either break the procedure into several smaller
procedures, or add labels to some of your statements.
The statement is too large for the compiler. Break it into several smaller
statements.
No definition for this label was found. See sections 3.3 and 6.3.
14-18
PL/M-86 User's Guide Error Messages
The program has too many complex expressions, cases, and procedures.
Break it into smaller modules.
NOTE
If a terminal error is encountered, program text beyond the point of error is
not compiled. A terminal error message will appear at the point of error in
the program listing.
14-19
Error Messages PL/M-86 User's Guide
PL/M-86 ERROR -
F I LE :
NAME:
ERROR:
COMPILATION TERMINATED
The errors that may occur due to insufficient memory are as follows:
14-20
PLjM-86 User's Guide Error Messages
14-21
APPENDIX A
PL/M-86 RESERVED WORDS
AND PREDECLARED IDENTIFIERS
These are the reserved words of PL/M-86. They may not be used as identifiers.
ADDRESS INITIAL
AND INTEGER
AT INTERRUPT
BASED LABEL
BY LITERALLY
BYTE MINUS
CALL MOD
CASE NOT
CAUSEINTERRUPT OR
DATA PLUS
DECLARE POINTER
DISABLE PROCEDURE
DO PUBLIC
DWORD REAL
ELSE REENTRANT
ENABLE RETURN
END SELECTOR
EOF STRUCTURE
EXTERNAL THEN
GO TO
GOTO WHILE
HALT WORD
IF XOR
These are the identifiers for the built-in procedures and predeclared variables. If one
of these identifiers is declared in a DECLARE statement, the corresponding built-in
procedure or predeclared variable becomes unavailable within the scope of the
declaration.
ABS INPUT
ADJUSTRPL INT
BLOCKINPUT INTERRUPTPTR
BLOCKINWORD INWORD
BLOCKOUTPUT LAST
BLOCKOUTWORD LOCKSET
BUILDPTR LENGTH
CARRY LOW
CMPB MEMORY
CMPW MOVB
DEC MOVE
DOUBLE MOVRB
FINDB MOVRW
FINDRB MOVW
FINDRW NIL
FINDW OFFSETOF
FIX OUTPUT
FLAGS OUTWORD
FLOAT PARITY
GETREALERROR RESTOREREALSTATUS
HIGH ROL
lABS ROR
INITREALMATHUNIT SAL
A-I
PLfM-86 Resened Words and Predeclared Identifiers PLfM-86 User's Guide
SAR SIZE
SAVER EAlSTATU S SKIPB
SCl SKIPRB
SCR SKIPRW
SElECTOROF SKIPW
SETB STACKBASE
SETINTERRUPT STACKPTR
SETW TIME
SHl UNSIGN
SHR XLAT
SIGNED ZERO
A-2
PROGRAM
BI
APPENDIX
CONSTRAINTS
Certain fixed size tables within the compiler constrain various features of a user
program to certain maximums. These limits are summarized below:
MAXIMUM:
NOTE
The PL/M-86 compiler has a symbol capacity of approximately 5000
symbols. Of these, 800 are held in memory when the compiler has a partition
size of 96K. Any symbols over this amount will spill onto the workfiles disk,
causing performance degradation. (If this happens, the compiler will display
a message to the console.) To increase performance, look at the dictionary
summary (found in the compilation summary) to determine the amount of
additional memory needed to avoid spilling to the disk. If another 64K of
memory is added to the compiler's partition (either by adding more memory
to the system or by increasing its share of available memory), a total of 2300
symbols will then be held in memory. For large programs or programs with
many symbols, providing the compiler with more memory to work in will
improve its performance.
B-1
APPENDIX C
GRAMMAR OF THE
PL/M-86 LANGUAGE
This appendix lists the entire syntax of the PL/M-86 language Backus Naur Form
(BNF). Since the semantic rules are not included here, this syntax permits certain
constructions that are not actually allowed. The terminology used in the BNF syntax
has been designed for convenience in constructing concise and rigorous definitions.
Its appearance differs substantially from the main body of the manual.
The notations used here are slightly extended from standard BNF notations. An
ellipsis (. .. ) indicates that the syntactic element preceding it may be repeated indefi-
nitely. Braces ({ }) indicate that only one of the items stacked vertically within
them may be used. Brackets ([ ]) indicate that whatever appears within them may
be omitted. When items are stacked vertically within brackets, only one of the items
may be used.
The nonterminals in the syntax that follows are listed in alphabetical order after
section C.5.3. Each nonterminal is tagged with the section number (within this
appendix) where its primary definition may be found.
c. 1 Lexical Elements
C. 1. 1 Character Sets
<character>:: = <apostrophe>
I <non-quote character>
<upper case letter>::=AI BI·CIDIEI FIG I HIIIJ I KI LI MIN 101 PlaiR IS ITI UIV IWIXIYI Z
<lower case letter>::=al bl cl dl e If Ig I h Ii Ij I kill min 101 plq I r Is It I u Iv I w I x I YIz
<decimal digit>::=OI11213141516171819
<special character>:: = + I-I *1/1 < I > 1= I: I; 1.1,1 (I)I@I_
<apostrophe>:: ='
C.1.2 Tokens
<token>:: = <delimiter>
I <identifier>
<reserved word>
<numeric constant>
<string>
C-I
Grammar of the PL/M-86 Language PL/M-86 User's Guide
C.1.3 Delimiters
<delimiter>:: = <simple delimiter>
I <compound delimiter>
<binary digit>: : = 0 11
<octal digit>:: = <binary digit> 12 131415 1617
<decimal digit>:: = <octal digit> I 8 I 9
<hexadecimal digit>:: = <decimal digit> I A I B I C I 0 I ElF
C.1.6 Strings
<string>:: = <string body element>
I
C-2
PL/M-86 User's Guide Grammar of the PL/M-86 Language
<separator>:: = blank
I <comment>
C.3 Declarations
<declaration>:: = <declare statement>
I <procedure definition>
C-3
Grammar of the PL/M-86 Language P~/M-86 User's Guide
<constant attribute>::=DATA
C-4
PLfM-86 User's Guide Grammar of the PLfM-86 Language
<interrupt> }
PUBLIC
{
REENTRANT
C.3.9 Attributes
C.3.9.1 AT
<locator>: : = AT ( <expression> )
C.3.9.2 INTERRUPT
<interrupt>:: = INTERRUPT <numeric constant>
C.3.9.3 Initialization
<initialization>:: =
jINITIAL}
DATA
( <initial value> (,<initial value>] ... )
C.4 Units
<unit>: : = <conditional clause>
I <do block>
<basic statement>
<label definition> <unit>
C-5
Grammar of the PL/M-86 Language PL/M-86 User's Guide
C-6
PLfM-86 User's Guide Grammar of the PLJM-86 Language
C.4.4 DO Blocks
<do block>::= <simple do block>
I <do-case block>
<do-while block>
<iterative do block>
C-7
Grammar of the PL/M-86 Language PL/M-86 User's Guide
c.s Expressions
C.S.1 Primaries
<primary>:: = <constant>
I <variable reference>
<location reference>
<subexpression>
<subexpression>:: = ( <expression> )
c.s.t.t Constants
<constant>:: = <numeric constant>
I <string>
{~rV'ri'ble reference>
C.S.2 Operators
<operator>: : = <logical operator>
I <relational operator>
I <arithmetic operator>
C-8
PL/M-86 User's Guide Grammar of the PL/M-86 Language
<or operator>:: = OR
I XOR
NONTERMINALS SECTION
C-9
Grammar of the PLfM-86 Language PLfM-86 User's Guide
C-IO
PL/M-86 User's Guide Grammar of the PL/M-86 Language
C-ll
APPENDIX
PL/M-80 AND PL/M-86
01
D. 1 General Comparison
PLfM-86 may be regarded as an extension of the PLfM-80 language, described in
Intel document 9800268. PL/M-86 differs from PL/M-80 in three principal respects:
• Floating-point arithmetic and signed integer arithmetic are provided. These are
supported by two new data types, REAL and INTEGER.
• The extended addressing capability of the iAPX 86 is supported by two new data
types, POINTER and SELECTOR, for storage of iAPX 86 locations, and a new
location reference operator, @.
• The set of built-in procedures is greatly expanded.
The PLfM-86 rules for expression evaluation are more complete than those of
PLfM-80, to make proper use of the extended capabilities. There are also various
other differences which stem from the ones noted here. In particular, an iterative DO
block operates differently if its index variable is an INTEGER variable.
Note that where PLfM-86 programs would normally have POINTER variables and
location references formed with the @ operator, PLfM-80 programs have ADDRESS
(WORD) variables and location references formed with the "dot" operator.
PLfM-80 usage is therefore slightly less restricted than normal PL/M-86 usage, since
arithmetic operations are allowed on WORD values. To provide upward compatibil-
ity, the PLfM-86 compiler in general supports PL/M-80 usage. However, some
restrictions are imposed, affecting the types of expressions allowed in the AT attrib-
ute, the INITIAL and DATA initializations, and location references. See also the
discussions of size controls and the dot and @ operators in this manual.
(In fact, all of these constructions are formally permitted by the PL/M-86 language,
but their use in PLfM -86 programs is not recommended for most purposes, since
they will not always produce correct results in a program where POINTER values
also appear.)
0-1
I
. ~
APPENDIX EI
ASCII CODES
E-l
APPENDIX F
LINKING TO MODULES WRITTEN
IN OTHER LANGUAGES
This appendix describes the calling conventions used by iAPX 86 family languages.
These calling conventions are standardized so that a module written in PLfM-86 can
freely call procedures, subroutines, and subprograms in other modules written in other
iAPX 86 family languages.
As a PLfM-86 programmer calling ASM86 subroutines, you need to know the calling
conventions of stack and register usage described in this appendix. You also need to
know the corresponding data types listed at the end of this appendix in order to write
a subroutine that can pick up the data your PLfM-86 program passes to it. Refer to
the ASM86 Macro Assembler Operating Instructions for more information about
linking to ASM86 programs and for examples of linking such programs to PLfM-86
programs.
F. 1 -Introduction
Since PLfM-86 allows you to write and compile separate PLfM-86 modules that can
be linked together at a later time, you can solve a big problem with a solution composed
of separately-tested modules that are linked together after they are internally bug-
free. Not all modules have to be in PLfM-86-you can choose the appropriate
languages for each module. Be sure to link the modules properly with the iAPX 86
Linker (LINK86) to satisfy references to externals. Since the iAPX 86 family
languages follow the same calling sequence (described in the following section), control
will pass to a called module correctly. However, the called module might not be able
to deal intelligently with the data passed to it since languages treat some data
structures differently.
All arguments for parameters are passed on the iAPX 86 stack or the 8087 register
stack in the order in which they were specified. Functions that return values return a
simple-type value (except REAL values) in a register, or a REAL value on the top
of the 8087 register stack.
F-l
Linking to Modules Written in Other Languages PL/M-86 User's Guide
Parameters are placed on the iAPX 86 stack or the 8087 register stack in left-to-
right order. Since the stack grows from higher locations to lower locations, the first
parameter occupies the highest position on the stack, and the last parameter occupies
the lowest position. Note that a BYTE parameter occupies two bytes on the stack;
the lower byte holds the value, the higher byte is undefined. A POINTER parameter
in the SMALL(ROM), COMPACT, MEDIUM, and LARGE cases consists of a
selector and an offset. The 16-bit selector is pushed first, followed by the 16-bit offset.
The leftmost seven REAL parameters are passed on the top of the 8087 stack. If
more than seven REAL parameters are present, the rest (after the leftmost seven)
are passed on the iAPX 86 stack.
After the parameters are passed, the CALL instruction places the return address on
the stack. In the SMALL and COMPACT cases with local procedures, this is a
16-bit offset (the contents of the IP register) and occupies two contiguous bytes on
the stack.
In the MEDIUM and LARGE cases, and for procedures exported from COMPACT,
the type of the return address depends on whether the procedure is local or public.
The return address for a local procedure, like any return address for the SMALL
case, is a 16-bit offset and occupies two contiguous bytes on the stack. For a public
procedure in the MEDIUM or LARGE case, and for procedures exported from a
subsystem, the return address is a POINTER value consisting of a selector and an
offset; it is passed in the same way a POINTER parameter is passed. The 16-bit
segment selector (contents of the CS register) is pushed first, then the 16-bit offset
(IP register contents) is pushed.
Figure F-l shows the stack layout at the point where the procedure gains control.
HIGHER
I-----------t......-. STACK MARKER (BP REG. CONTENTS)
LOCATIONS
PARAMETER 0
PARAMETER 1
EACH PARAMETER OCCUPIES 2 OR 4
BYTES-SEE TEXT
PARAMETER N
RETURN OFFSET
~g~::'ONS t---------~~ STACK POINTER (SP REG. CONTENTS)
121945·5
F-2
PL/M-86 User's Guide Linking to Modules \yritten in Other Languages
Control then passes to the code compiled from the executable statements in the
procedure body. Figure F-2 shows the stack layout at this point.
PARAMETER 0
HIGHER PARAMETER 1
LOCATIONS ABSENT IF ANY PARAMETER IS
REFERENCED WITHIN A NESTED PROCEDURE
}
PARAMETERN
RETURN OFFSET
LOWER
LOCATIONS
121945-6
F-J
Linking to Modules Written in Other Languages PL/M-86 User's Guide
If the program size is MEDIUM or LARGE and the procedure is local, a return is
performed using the same actions described above. If the program size is MEDIUM
or LARGE and the procedure is public, the stored return-address offset from the
stack is popped into the IP register and the return-address selector is popped into the
CS register. Any parameters not stored on the stack are discarded.
In addition, the 8087 stack contains the first seven REAL arguments passed by the
calling program. The 8087 status word is unknown and need not be saved; if it is
changed, the 8087 mode word must be saved on entry and restored before exit.
PLfM-86 uses the BP register to address the stack. If it uses the BP register, a called
assembly language subroutine must save the contents of this register upon entry and
restore its contents before returning control to the PLfM-86 program. Before return-
ing, the called subroutine must also adjust the SP register to remove all
parameters from the iAPX 86 stack.
The AX, BX, CX, DX, SI, DI, and ES registers do not need to be preserved. A called
assembly language subroutine can freely use these registers.
Table F-2 summarizes the iAPX 86 registers used to hold simple data types that are
returned by typed procedures.
F-4
PL/M-86 User's Guide Linking to Modules Written in Other Languages
• SP must be adjusted so that all arguments are removed from the stack upon return.
BYTE AL
WORD AX
OWORO OX:AX
INTEGER AX
POINTER (SMALL)· BX
POINTER (COMPACT) ES:BX
POINTER (MEDIUM) ES:BX
POINTER (LARGE) ES:BX
SELECTOR AX
REAL Top of
RMU stack
F-5
Linking to Modules Written in Other Languages PLjM-86 User's Guide
NOTES:
sCODE denotes a segment name composed of the subsystem name and CODE.
sDATA denotes a segment name composed of the subsystem name and DATA.
meODE denotes a segment name composed of the module name and CODE.
rnDATA denotes a segment name composed of the module name and DATA.
These linkage specifications make available to your program the libraries of floating-
point functions. The circumstances determining whiCh library is appropriate are given
in table F-4. The libraries themselves are discussed briefly below the table.
F-6
PL/M-86 User's Guide Linking to Modules Written in Other Languages
NOTE
The 8087 Emulator processes exceptions exactly as the 8087 does. However,
if your iAPX 86/8087 implementation includes some external interrupt
masking device such as an 8259A, the effect of this external device cannot
be simulated by the 8087 Emulator. With the Emulator, an Interrupt 16 will
occur after the execution of any instruction when the (emulated) interrupt is
active and the iAPX 86 interrupt is enabled, even" if the 8259A is disabled.
(For examples of how to link interface libraries with your program, see specific host-
system appendix.)
F-7
APPENDIX G
RUN-TIME INTERRUPT PROCESSING
G. 1 General Information
An interrupt is initiated when the CPU receives a signal on its "maskable interrupt"
pin from some peripheral device or when control is transferred to an interrupt vector
by the CAUSE$INTERRUPT statement. (If your program runs under an operating
system that traps interrupts, the information in this appendix may not be applicable
to you.)
Note that the CPU does not respond to this signal unless interrupts are enabled. The
compiler does not generate any code to enable or disable interrupts at the start of
your main program.
NOTE
If you require your program to begin with interrupts disabled, simply start
with the instruction DISABLE. Since the iAPX 86 processor does not allow
an interrupt to occur until the first machine instruction following the enable
instruction has been processed, the resulting code sequence will not allow any
maskable interrupt to occur.
If interrupts are enabled and vectored through an interrupt gate, the following actions
take place:
1. The CPU completes any instruction currently in execution.
2. The CPU issues an "acknowledge interrupt" signal and waits for the interrupting
device to send an interrupt number.
3. The CPU flag registers are placed on the stack (occupying two bytes of stack
storage).
4. Interrupts are disabled by clearing the IF flag.
S. Single stepping is disabled by clearing the TF flag.
6. The CPU activates the interrupt procedure corresponding to the interrupt number
sent by the interrupting device.
7. When that procedure terminates, the stack is automatically restored to the state
it was in when the interrupt was received, and control returns to the point where
it was interrupted.
The mechanism for this activation and restoration are described below.
G-I
Run-Time Interrupt Processing PLfM-86 User's Guide
Note that the first and second bytes of each entry contain an offset, while the second
two bytes contain a segment address. The entries are always four-byte pointers, and
the segment address is always used in transferring to the interrupt procedure, even if
the program size is SMALL.
The CPU uses the interrupt vector entry to make a long indirect call to activate the
appropriate procedure. At this point, the current code segment address (CS register
contents) and instruction offset {IP register contents) are placed on stack.
At the point where the procedure is activated, the stack layout is as shown in
figure G-l.
At the beginning of each interrupt procedure, the interrupt procedure prologue inserted
by the compiler accomplishes the following:
1. Pushes the CPU registers to the stack in the following order-AX, ex, DX, BX,
(SP and BP on the iAPX 186 only), SI, and DI.
2. Pushes the ES register contents onto the stack.
3. Pushes the DS register contents onto the stack.
4. Loads the DS register with a new data segment address taken from the current
code segment (i.e., the segment containing the interrupt procedure).
5. Pushes the BP register contents onto the stack.
6. Loads the stack marker (BP register) with the address taken from the current
stack pointer (SP register).
7. If the procedure is REENTRANT, reserves space on the stack for any local
variables declared in the procedure.
HIGHER
FLAG REG. CONTENTS 2 BYTES
~~ ~----------------~
PROGRAM SIZE
1-;:)
en 8 RETURN OFFSET
~----------------~....-... STACK POINTER
LOWER
LOCATIONS
121945-5
Figure G-l. Stack Layout at Point Where an Interrupt Procedure Gains Control
0-2
PL/M-86 User's Guide Run-Time Interrupt Processing
NOTE
The compiler may make temporary use of the DS register in some cases
(e.g., string built-ins), but always restores it. Care must be taken when writing
your own interrupt procedure in assembly language to note this possibility.
After the interrupt procedure prologue is executed (at the point where the code
compiled from the procedure body gains control), the stack layout is as shown in
figure G-2.
The return from the procedure body is called the interrupt procedure epilogue; it
restores the stack to the state it was in before the interrupt occurred. The interrupt
procedure epilogue contains the following steps:
8. If stack locations were used for temporary storage or local variables, loads the
stack pointer (SP register) with the current stack marker (BP register). This
discards the temporary storage.
9. Pops the stack into the BP register, restoring the old stack marker.
10. Pops the stack into the OS register.
11. Pops the stack into the ES register.
12. Pops the stack into the CPU registers in the following order-OI, SI (BP on the
iAPX 186 only), BX, OX, CX, AX. Note that the SP register value is discarded
by the POP A instruction on the iAPX 186.
13. Executes an IRET instruction to return from the interrupt procedure. This restores
the IP, CS, and the flag register contents from the stack.
HIGHER
LOCATIONS
FLAG REG. CONTENTS
I ~BYTES
RETURN OFFSET
AX REG. CONTENTS
CX REG. CONTENTS
OX REG. CONTENTS
BX REG. CONTENTS
186
1SP REG. CONTENTS
>- CPU STATUS INFORMATION
BP REG. CONTENTS
a:: SI REG. CONTENTS
w 01 REG. CONTENTS
I-
Z ES REG. CONTENTS
::J
o(.) OS REG. CONTENTS
:.::
~
(.)
<I:
'-- OLD STACK MARKER
l- . . . . . - NEW STACK MARKER (BP REG. CONTENTS)
V)
LOCAL VARIABLES
121636-4
G-3
Run-Time Interrupt Processing PL/M-86 User's Guide
If the procedure is REENTRANT and has local variables, steps 8 and 9 will be
replaced by the LEAVE instruction (see the iAPX 186 Programmer's Reference
Manual).
At this point, the stack has been restored to the state it was in before the interrupt
occurred, and processing continues normally.
In some cases it may be desirable to write the interrupt vector separately (in
PL/M-86 or assembly language). This can be done by using NOINTVECTOR to
prevent generation of an interrupt vector by the compiler. The separately created
interrupt vector can then be linked into the program.
Creation of a separate explicit interrupt vector requires some care. The @ operator
in PL/M-86 provides access to a procedlJre's normal (i.e., called) entry point, not to
its interrupt entry point. The interrupt entry point first saves the status of the inter-
rupted program before invoking the interrupt procedure through its normal entry
point. The exact length of these operations depends on the compilation options chosen,
the attributes of the interrupt procedure, and the version of the compiler being used.
The built-in function INTERRUPTSPTR can be used during execution to return the
actual interrupt entry point. Discussion of this function appears in Chapter 9.
Suppose that two modules for a multimodule program are developed separately. Both
use interrupt procedures, but at the time when the modules are written the assign-
ment of interrupt numbers to the various interrupt procedures has not been
determined.
The two modules are therefore compiled with the NOINTVECTOR control. When
this is done, the n in an INTERRUPT n attribute is ignored-since normally it would
only be used to put the procedure's entry in the proper location within the interrupt
vector.
Later, when the program is linked together, a separately created interrupt vector can
be linked in. Within this interrupt vector, the placement of the entry for a given
interrupt procedure determines which interrupt vector, the placement of the entry for
a given interrupt procedure determines which interrupt number will activate that
procedure.
0-4
PL/M-86 User's Guide RUD-Time mterrupt Processing
• Zero divide
• Overflow
• Underflow
• Precision
These exceptions are discussed in order below. In each case, only a few of the possible
causes are described because most are not likely to occur with PL/M-86 usage. If
you want to perform sophisticated numeric processing of extreme precision and flexi-
bility, see the iAPX 86,88 User's Manual.
The six exceptions and their default responses are summarized in table G-l.
As the following sections indicate, the masked, default response to most exceptions
will provide the least abrupt, most appropriate action for PL/M-86 applications. Many
real math exceptions that occur in other processors will not occur with the 8087
because of the extended range of intermediate results it holds. The "soft" recovery of
gradual underflow (described under the denormal exception), also extends the range
of permissible execution rather than reporting a hard-failure condition.
Programmers who use the recommended setting of the REAL Mode Word (see section
10.4 ) need to handle only the invalid exception. Study of the other exception
conditions is advised, however, to provide a general understanding of their use.
Invalid If one operand is NAN, return it; Request interrupt. (8087 stack
Operation if both are NANs, return NAN with unchanged.)
larger absolute value; if neither is
NAN, return indefinite NAN.
Zerodivide Return co signed with "exclusive Request interrupt. (8087 stack
or" of operand signs. unchanged.)
Denormalized Memory operand: proceed as Request interrupt. (8087 stack
usual. unchanged.)
Register operand: convert to valid
unnormal, then reevaluate for
exceptions.
Overflow Return properly signed 00. Register desti nation: adjust
exponent, * store result, request
interrupt.
Memory destination: request
interrupt.
Underflow Denormalize result. Register destination: adjust
exponent, * store result, request
interrupt.
Memory destination:; request
interrupt.
Precision Return rounded result. Return rounded result, request
interrupt.
* On overflow, 24,576 decimal is subtracted from the true result's expone~t; this forces·the exponent
back into range and permits a user exception handler to ascertain the true result from the adjusted
result that is returned. On underflow, the same constant is addedto the true result's exponent.
G-5
Run-Time mterrupt Processing PL/M-86 User's Guide
Another interpretation of this exception is stack error. This may be caused by failing
to restore the math unit status before returning from an interrupt routine that had
saved the status. Another cause is the generation of more than 8 intermediate results
during REAL arithmetic, which can arise if REAL procedure function calls are nested
too deeply. The compiler ensures that no single procedure does this, but cannot check
what may occur only at run time. This exception can also occur when REAL functions
(typed procedures) are used as operands within longer REAL expressions.
For example:
Since the evaluation of such an expression also involves the use of this stack for prior
and subsequent arithmetic operations, stack overflow may occur. This overflow
amounts to unpredictable destruction of original parameters or intermediate results.
It becomes more likely as you increase the complexity of REAL expressions contain-
ing REAL functions. Thus, you are safer using an assignment statement first to store
the function's value in a real variable-and using that variable in the larger
expression.
If stack error might apply to your program, modify the code for the affected proce-
dures to call the built-in procedures SA VE$REAL$ST ATUS and
RESTORE$REAL$ STATUS as their first and last operations, respectively.
The masked (default) response is to set the result to one of the special bit patterns
called Not-A-Number (NANs), usually the indefinite value, the smallest NAN
representable in the specified precision. It also sets Bit 0 of the REAL Error Byte.
This condition arises when numeric operations have resulted in a number whose
exponent is literally zero and whose significand is non-zero, or a number whose sign i-
ficand does not begin with a one. Denormals usually arise in response to masked
underflow. Gradual underflow is the masked, default response to underflow. A small
G-6
PL/M-86 User's Guide Run-Time Interrupt Processing
denormal added to a large normal REAL number can give an acceptable, in-range
answer if the denormal exception is masked. In practice, denormals are very rare
since intermediate results are kept in temporary real format (I5-bit exponent).
This condition causes Bit 1 of the REAL Error Byte to be set to 1. If Bit 1 of the
REAL Mode Word is 1, the response described above occurs; if Bit I is 0, an
interrupt occurs, transferring control to the user-written interrupt handler.
This condition arises when in the course of some REAL computation a divisor turns
out to be zero. The masked response, when Bit 2 of the REAL Mode Word is 1, is to
return infinity appropriately signed. If Bit 1 is 0, an interrupt occurs, giving control
to the user-written interrupt handler. In either case, Bit 2 of the REAL Error Byte
is set to 1.
Overflow Exception
This error occurs when a real result is too large for the format in use. For REAL
assignments, it occurs if the result is greater than about 3.37 X 1038 ; for intermediate
REAL computations, if the result is greater than about 104932 • The overflow exception
can arise during assignment, addition, subtraction, multiplication, division, or
conversion to integer.
The masked, default response (Bit 3 of REAL Mode Word = 1) is to return infinity
(signed if Affine Mode is set) and set Bit 3 of the REAL Error Byte to 1. Unmasked
overflow must go through a user-written interrupt handler.
Underflow Exception
Underflow exception is caused by an exponent too small for the format in use. For
REAL assignments, it occurs if the exponent is less than -127, and for intermediate
results if the exponent is less than -16383. Underflow can be caused by the same
type of REAL operations as overflow.
The masked, default response (Bit 4 of REAL Mode Word = 1) is to use the denor-
mal number created by adjusting the very small result. It adjusts the significand,
moving significant digits off to the right and raising the exponent until the latter
becomes non-zero. For example, a 24-bit significand of .01 with an exponent of zero
implies the number 1 X 2- 129 because a zero exponent in this format means -127. If
the denormal exception is masked, this would be adjusted into a significand of .001
with an exponent of 1, i.e., 0.001 x 2- 126, prior to operation. This number would then
be available for use in subsequent REAL operations that might yield valid results.
Zero is returned if it is the rounded result. Bit 4 of the REAL Error Byte is set to 1.
Unmasked underflow must go through a user-written interrupt handler.
Precision Exception
This error occurs when the result of an operation is inexact (i.e., rounded) or when"
an overflow exception occurs. No special action is performed by a masked response
(Bit 5 of REAL Mode Word = 1) other than setting Bit 5 of the REAL Error Byte.
Unmasked response is as chosen by the user.
G-7
Run-Time Interrupt Processing PLfM-86 User's Guide
or:
Each procedure clears the error byte. The latter procedure also clears out the REAL
stack. Thus, after either procedure is used, the REAL Error Byte no longer contains
the flagged cause of the exception condition that invoked HANDLER.
Thus, the beginning of a typical routine to handle REAL exception conditions could
look like this:
G-8
PLjM-86 User's Guide Run-Time Interrupt Processing
or, if you want to perform extensive manipulations on the save area, you could declare
a structure permitting you access to its component parts by name and/or byte, as
follows:
The rest of HANDLER can perform any actions deemed appropriate. This is an
application-dependent decision. Among the possibilities:
• Incrementing an exception counter for later display
• Printing diagnostic data, e.g., the contents of SAVE-AREA
• Aborting further execution of the calculation causing exception
• Aborting all further execution
The final action prior to returning (if desired) to the interrupted procedure is to restore
the status of the REAL math unit:
G-9
Run-Time Interrupt Processing PLJM-86 User's Guide
INCREASING ADDRESSES
15
CONTROL WORD ~l
;..---.t::
STATUS WORD
TAG WORD +4
INSTRUCTION
POINTER
{ IP 15-0
IP 32-16
+6
+8
OPERAND
POINTER
{ OP 15-0
OP 32-16
+10
+ 12
SIGNIFICAND 15-0 + 14
SIGNIFICAND 31-16 +16
TOP STACK
ELEMENT:ST -< SIGNIFICAND 47-32 -t 18
sl•
SIGNIFICAND 63-48 +30
~~ ~ :::
SIGNIFICAND 15-0 +84
LAST STACK
ELEMENT:ST(7) ~ SIGNIFICAND 47-32 +88
NOTES:
S = Sign
BIT 0 OF EACH FIELD IS RIGHTMOST, LEAST SIGNIFICANT BIT OF CORRESPONDING
REGISTER FIELD.
BIT 63 OF SIGNIFICAND IS INTEGER BIT (ASSUMED BINARY POINT IS IMMEDIATELY
TO THE RIGHT).
SAVE_AREA.STATUS (0) 0;
G-IO
APPENDIX H
COMPILER INVOCATION AND ADDITIONAL
INFORMATION FOR SERIES III USERS
This appendix contains information that is specific to the Intellec Series III Micro-
computer Development System. It covers the following areas:
• Compiler invocation and file usage
• Examples of system-dependent compiler controls
• Related publications
This compiler runs under ISIS V4.1 with RUN V1.2, ISIS V4.2 with RUN V1.3, or
later versions of both products.
You create a PL/M program by using the CREDIT text editor to type instructions
into a file, and then submitting the file to the PL/M-86 compiler. The file you submit
is called a source file, and the file containing the compiled program is called an object
file. (The content of the object file is also known as object code.) In
PL/M-86, you can compile parts of a program. Each separate compilation is known
as an object module.
The following discussion assumes that you have a Series III system up and running,
and that you have a suitable copy of the PL/M-86 compiler. Details on the
operating system environment are provided in the Intellec Series III Microcomputer
Development System Console Operating Instructions.
R U H [: F d: 1 P L M8 6 [: F d: ] source [controls] (c r )
where
RUN is the name of the command used to execute the compiler.
:Fd: specifies on which drive, if not drive 0, the PL/M-86 compi-
ler and/or source program resides. (The source file does not
have to be on the same drive as the compiler.)
PLM86 is the name you use for the compiler PLM86.86.
source is the name of the source file containing the PL/M-86
program.
controls are optional compiler controls -described in Chapter II. You
can have many controls on the invocation line· if you use a
space between each control, and you can extend the invoca-
tion line by using the ampersand (&) as a continuation
character.
<cr) stands for use of the RETURN key on the keyboard.
Examples:
H-l
Compiler Invocation and Additional Information for Series III Users PL/M-86 User's Guide
In this example, the compiler is on drive 0, but MYPROG.SRC, the source program,
is on drive 1. The compiler will direct all printed output to :LP:, and place 'TEST
PROGRAM 4' in the header on each page of the listing.
In this example, both the compiler and the source program (PROG1.SRC) are on
drive 1. NOPRINT will prohibit all printed output (except error messages) usually
generated by the compiler.
Input Files
The compiler reads the PL fM -86 source from the source file specified on the command
line (see previous section) and also from any files specified with INCLUDE controls
(as described in Chapter 11). These files must be standard ISIS-II disk files. The
source input should contain a PLfM-86 source module.
Output Files
Two output files are produced during each compilation unless specific controls are
used to suppress them. The output files are the listing and object code files. Each of
these may be explicitly directed to some standard Series II pathname (device or file)
by using the PRINT and OBJECT controls, respectively. If the user does not control
these outputs explicitly, the compiler writes them to disk files on the disk containing
the input file. These files then have the same file name as the input file but have the
extensions LST for the listing and OBJ for the object code. For example, if the
compiler is invoked by:
the listing and all other printed output is written to :Fl :MYPROG.LST and the object
code to :Fl:MYPROG.OBJ. If these files already exist, they are overwritten. If they
do not exist, the compiler creates them.
The object code file may be used as input to the ISIS-II linkage facilities. (See the
iAPX 86 Utilities User's Guide).
The work files used by the compiler during its operation are deleted at the end of
compilation. All of these files are on the device: WORK:.
All of the work files have names with the extension TMP. Therefore, you should
avoid naming files with the extension TMP on any device used by the compiler for
work files-the operation of the compiler may destroy them.
H-2
PL/M-36 User's Guide Compiler Invocation and Additional Information for Series III Users
If you do not have a 8087 chip installed in your system, the correct linking statement
is:
A summary description of the set of manuals that describe the Intellec Series III
development system and its supporting hardware and software. This short manual
includes a description of each manual related to the Series III, plus a glossary of
terms used in the manuals.
Instructions for using the console features of the Series III, including the resident
monitor. The Conssole Operating Instructions provides complete instructions, and
the Pocket Reference gives a summary of this information.
Instructions for calling system routines from user programs for both microprocessor
environments (8080/8085 and 8086) in the Series III.
Instructions for using CREDIT, the CRT-based text editor supplied with the Series
III. The User's Guide provi,des complete operating instructions, and the Pocket
Reference summarizes this information for quick reference.
H-3
Compiler Invocation and Additional Information for Series m Users PL/M-86 User's Guide
Instructions for using the utility programs LINK86, LIB86, LOC 86, CREF86, and
OH86 in iAPX 86-based environments to prepare compiled or or assembled programs
for execution.
Instructions for using the ICE-86 and ICE-88 In-Circuit Emulators for hardware and
software development. The Operating Instructions manuals give complete user
descriptions of the In-Circuit Emulators, and the Pocket Reference guides provide
summary information for quick reference. You need the corresponding publications
if you are using the ICE-86 or ICE-88 emulator.
H-4
PL/M-86 User's Guide Compiler Invocation and Additional Information for Series III Users
Causes file TEST6.0BJ (on drive 1) to include informa- DEBUG/NODEBUG RwN PLI'r186 :'1:iES-6,SRC DB (cr)
tion that will later be used to debug the program using
a symbolic debugger.
Causes source lines from file SYSLlB.SRC (on drive 1) INCLUDE RJN D~'18o 5'SPR=',SR~ &
to be placed in file SYSPRG.SRC (on drive 0). :N~~I"!J~(:rl :S'lSL:B,5R2) (cr)
Sends file PROG1.0BJ to the disk in drive 1 instead of OBJECT INOOBJECT RlN Cl_~85 :JR~0',SR= &
drive 0 (the default location). =B~:=-(::-':PRO:",=3J) <:r>
Prints file TSTLlB.LST with a pagewidth of 70. PAGEWIDTH RUN P~1'r18o TST,-!B,SRC PIH70) (cr)
Causes the subtitle 'Module One' to appear on every SUBTITLE RLN ;::L~8o :='::N:-i,SRC &
page until another subtitle control (if any) appears in SvE-:i~~(\Y=:::J~: =!-,E') (C"J
INIT1.SRC on drive 1.
Causes the title 'TEST PROGRAM 5' to appear on every TITLE R\.~ ~_~8c ::~=~~.J~= ~
page. ...:..-_~(\.,.-t:s~ ::;;:3RH Y 5') <c,..}
H-5/H-6
APPENDIX I
COMPLERINVOCATION AND ADDITIONAL
INFORMATION FOR iRMX™ 86 USERS
This appendix contains information that is specific to the iRMX 86 Operating System.
It covers the following areas:
• System requirements
• Compiler invocation and file usage
• Examples of system-dependent floating-point library linkage
• Examples of system-dependent compiler controls
• Related pUblications
I. 1 System Requirements
To run the compiler on an iRMX 86-based system, you must have the following
hardware and software:
• The iRMX 86 Human Interface (and other iRMX 86 layers necessary to support
the Human Interface).
• At least one mass storage device. The installation of the compiler always requires
a single- or double-density diskette drive, since the product is delivered in diskette
form.
• Enough memory to run the compiler (above and beyond that required for the
Operating System). This ranges from
minimum - 140K - Amount needed to run compiler assuming connection to only
six files
maximum - 512K - Largest amount the compiler can use.
You can invoke the PL/M-86 Compiler from the system console using the standard
command format described in the iRMX 86 Human Interface Reference Manual.
You can specify continuation lines by using the ampersand (&) as a continuation
character. The ampersand can appear any place there is a space or other delimiter.
where
directory is the portion of the pathname that identifies the device and
directories that contain the file PLM86. If you omit the
directory portion of the pathname, the Operating Systetn
automatically searches several directories for the file PLM86.
The directories searched and the order of search are
iRMX 86 configuration parameters.
1-1
Compiler Invocation aDd Additional Information for iRMX 86 Users PLfM-86 User's Guide
In the interactive sequence shown in figure I-I, comments appearing to the right of
semicolons are for clarification, not material entered by the user. This example shows
how to compile a complete program that does not require more than 64K bytes of
storage for the code or more than 64K bytes for the data.
In the normal usage, the PLfM-86 compiler writes the compilation listing by default
to a secondary storage file on the same device as the source file. This file has the
same pathname as the source file, but the last component of the pathname has the
extension LST. Thus, in the previous example, you can find the- listing in
:PROG:MYPROG.LST. Similarly, the object code file is' on the same device and has
the same pathname, but has the extension OBJ. In the example,
:PROG:MYPROG.OBJ contains the object code produced by compiling
:PROG:MYPROG.SRC.
Examples
1.
In this example, the compiler resides in a directory that the Operating System
automatically searches; thus it does not require a device or directory name. The
compiler is directed to compile the source module on :FI:PROGl.SOURCE. This
file resides on the device with logical name : F 1: and has the name
PROG.SOURCE.
2.
In this example, the compiler resides on device :FDO:. The compiler is directed
to compile the source module on :WDO:DIRI fMYPROG.SRC, send the output
listing to :LP:, and place 'TEST PROGRAM 4' in the header on each page of
the listing.
1-2
PL/M-86 User's Guide Compiler Invocation and Additional Information for iRMX 86 Users
The compiler reads the PL/M-86 source from the source path file specified on the
command line (see previous section) and also from any files specified with INCLUDE
controls (as described in Chapter II). These files must he standard iRMX 86 files.
The source input should contain a PL/M-86 source module.
Output Files
Two output files are produced during each compilation unless specific controls are
used to suppress them. These are the listing and object code files. Each of these may
be explicitly directed to some iRMX 86 file or device by using the PRINT and
OBJECT controls respectively. If the user does not control these outputs explicitly,
the compiler writes them to secondary storage files on the device containing the input
file. These files have the same pathname as the input file, but have the extensions
LST (for the listing) and OBJ (for the object code). For example, you invoke the
compiler with
The compiler writes the listing and all other printed output to :FI :MYPROG.LST
and the object code to :FI:MYPROG.OBJ. If these files already exist, the compiler
overwrites them.
The object code file may be used as input to the relocation and linkage facilities (see
the iAPX 86,88 Family Utilities User's GUide).
The compiler uses work files during its operation that are deleted at the completion
of compilation. All of these files are in the directory with logical name :WORK:
unless the WORKFILES control is used to specify another directory.
All of the work files have names with the extension TMP. Therefore, if you place
those files in the work files directory, you should avoid giving your files names with
the extension TMP, because there is a possibility that the compiler will destroy them.
In order to use the REAL math facility on the iRMX 86 Operating System, you
must have an 8087 Numeric Processor Extension installed on your iRMX 86 system.
In such a case, the correct linking statement is
More detailed and advanced discussions of the features and functions of the
iAPX 86 utilities appear in the iAPX 86,88 Family Utilities User's Guide.
1-3
Compiler layocatioo aad AdditionallnformatioD for iRMX86 Users PL/M-86 User's Guide
A general introduction to the iRMX 86 Operating System. This manual discusses the
features of the Operating System and introduces some of the terminology. It also lists
and describes each of the manuals in the iRMX 86 manual set.
Additional information about the Operating System that PL/M-86 users might
require.
Instructions for using EDIT, the text editor available for use on the iRMX 86
Operating System.
Instructions for using the utility programs LINK86, LIB86, LOC86, CREF86, and
OH86 in iAPX 86-based environments to prepare compiled or assembled programs
for execution.
1-4
PL/M-86 User's Guide Compiler Invocation and Additional Information for iRMX 86 Users
Instructions for using the 8086/8087/8088 macro assembly language and its assem-
bler in iAPX 86-based environments. The Language Reference Manual gives a
complete description of the assembly language. The Operating Instructions Manual
gives complete instructions for operating the assembler. You need these publications
if you are coding some of your routines in assembly language.
Instructions for calling procedures that implement the REAL math facility of the
808 7 Numeric Processor Extension.
1-5
PL/M-86 User's Guide Compiler Invocation and Additional Information for iRMX 86 Users
Causes input of source lines from file :WDO:INCLUDE/ INCLUDE INCLUDE(:WDD: INCLUDE/SYSLIB.SRC)
SYSLlB.SRC
1-7/1-8
INDEX
Index-l
Index PL/M-86 User's Guide
Index-2
PL/M-86 User's Guide Index
expression, 14, 3-2, 4-1 thru 4-15, 8-4 IF statement, 4-5, 4-11, 6-3, 6-7, 6-8
analysis, 4-6 thru 4-9 enclosing DO blocks, 6-8 thru 6-10
constant, 4-10 thru 4-14 nested, 6-8 thru 6-10
evaluation order, 4-9 implicit
floating-point, 3-11, 3-12 dimension specifier, 3-6
REAL, 3-11, 3-12 label declaration, 3-8
restricted, 3-4 type conversion, 4-13, 8-5
subscript, 5-2 INCLUDE control, 11-2, 11-32, 13-6, Appendix H,
summary of rules, 4-9 thru 4-14 Appendix I
extended scope, 7-4, 7-5, 8-7, 8-8 inclusive extent, 7-1 thru 7-3
extended segmentation controls, Chapter 13 index
extent, inclusive or exclusive, 7-1 thm 7-3 in string moves, 9-9
EXTERNAL, 3-1, 3-6 thm 3-9, 6-11, 7-4 thru 7-7, 8-7, variable, 5-2, 6-6
8-8, 11-23 see also DO, iterative
infinity control, Appendix G
factored declaration, 3-3 INIT$REAL$MATH$UNIT, 10-8
false, 3-11,4-5, 4-6,6-4,6-7 INITIAL, 3-1, 3-4 thru 3-7, 3-13, 7-5, 11-23
far references to procedures, Appendix F initializations, 3-4 thru 3-7
fatal errors, 14-20 multiple, 3-4
fields of a REAL number, 3-11 of REAL math facility, 10-6
file usage, Appendix H, Appendix I string constant, 2-5
FINDB,9-11 INPUT, 1-5, 10-4, 10-5
FINDRB, 9-11 inner level, 6-11
FINDRW, 9-11 see outer
FINDW,9-11 input/output, 1-5, 10-4, 10-5
FIX, 9-3, 9-5 ports, 1-5
FLAGS, 10-3 insertion sort example, Chapter 12
FLOAT, 9-3,9-5 INT, 9-3, 9-5
floating-point linkage, Appendix F INTEGER, 3-11,4-1 thru 4-4
floating-point number, 3-11, 3-12 least significant bits, 3-11
format in memory, 3-11 interface list, 13-4
flow control statements, 6-1 thru 6-12 intermediate results, 10-6, Appendix G
folding of constant expressions, 11-5 internal REAL format, 3-11
formal parameters, 8-2 thru 8-7 INTERRUPT attribute, 8-7 thru 8-9
fraction of REAL number, 3-11 interrupt
function, 8-4 attribute, 8-7
REAL,10-15 enabled or disabled, 8-8, 8-9, Appendix G
references, 4-2,4-9,4-12, 8-1 thru 8-5 emulator usage, Appendix F
see also built-in entry point, Appendix G
epilogue, Appendix G
gates, Appendix G
genera.l controls, 11-1 masking, Appendix F, Appendix G
GET$REAL$ERROR, 10-8, 10-9, Appendix G mechanism, 8-9, Appendix G
GOTO, 3-9, 6-2,6-11, 7-6 thru 7-9, 8-5, 8-9 prologue, Appendix G
gradual underflow, Appendix G procedures, 8-8 thru 8-10, Appendix G
grammar of PL/M-86, Appendix C REAL, 10-6, Appendix G
greater than, see relational signal, 8-8, 8-9
software, 9-13
HALT,10-1 vectors, 8-8, 11-4, Appendix G
hardware interrupt request, 10-6
features, Chapter 10 INTVECTOR control, 11-4
flags, 10-1 thru 10-3 invalid operation, Appendix G
registers, 10-3, 10-4 invocation
HIGH, 4-3, 9-4 line, Appendix H, Appendix I
high-level languages, 1-1, 1-2 of procedure, 1-3
HLT,10-1 INWORD, 1-5, 10-4, 10-5
iRMX, Appendix I
Index-3
Index PL/M-86 User's Guide
Index-4
PLjM-86 User's Gaicle Index
Index-5
Index PL/M-86 User's Guide
Index-6
PLfM-86 User's Guide Index
Index-7
PL/M-86 User's Guide
121636-003
Intel's Technical Publications Departments attempt to provide publications that meet the needs of all Intel product
users. This form lets you participate directly in the publication process. Your comments will help us correct and
improve our publications. Please take a few minutes to respond.
Please restrict your comments to the usability, accuracy, readability, organization, and completeness of this
publication. If you have any comments on the product that this publication describes, please contact your Intel
representative. If you wish to order publications, contact the Intel Literature Department (see page ii of this
manual).
1. Please describe any errors you found in this publication (include page number).
2. Does the publication cover the information you expected or required? Please make suggestions for
improvement.
3. Is this the right type of publication for your needs? Is it at the right level? What other types of publications
are needed?
5. Please rate this publication on a scale of 1 to 5 (5 being the best rating). _______________
COMPANY NAME/DEPARTMENT _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ __
ADDRESS ______________________
CITY ______________________ STATE _____________ ZIP CODe _ _ _ _ __
(COUNTRY)
This document is one of a series describing Intel products. Your comments on the back of this form will
help us produce better manuals. Each reply will be carefully reviewed by the responsible person. All
comments and suggestions become the property of Intel Corporation.
111111 NO POSTAGE
NECESSARY
IF MAilED
IN U.S.A.
Intel Corporation
Attn: Technical Publications MIS 6-2000
3065 Bowers Avenue
Santa Clara, CA 95051
INTEL CORPORATION, 3065 Bowers Avenue, Santa Clara, California 95051 (408) 987-8080
Printed in U.S.A.