mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-22 07:54:25 +00:00
352 lines
12 KiB
Plaintext
352 lines
12 KiB
Plaintext
|
||
PL/M-80 Language Summary
|
||
|
||
|
||
PL/M-80 is a programming language for i8080 systems. It is based most
|
||
notable on PL/I. It has the type of block structure and scope rules
|
||
most programmers now expect despite the fact it is a fairly small
|
||
language.
|
||
|
||
The one thing that may "trip-up" may Pascal programmers is that PL/M
|
||
(and its PL/I big brother) use semicolon as a terminator, not as a
|
||
statement separator. Semicolons mark the end of every statement.
|
||
|
||
The remainder of this file summarizes the PL/M-80 language and its
|
||
features. It is only a summary; no attempt is made to provide a
|
||
complete and unambiguous description.
|
||
|
||
PL/M Character Set
|
||
==================
|
||
Alphabetics: A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
|
||
Numerics: 0 1 2 3 4 5 6 7 8 9
|
||
Specials: $ = . / ( ) + - ' * , < > : ; and space
|
||
|
||
All other characters are unrecognized by PL/M in the sense that they
|
||
are regarded as equivalent to the space character.
|
||
|
||
PL/M Identifiers
|
||
================
|
||
Identifiers may be from 1 to 31 characters in length. An alphabetic
|
||
must be the first character in an identifer name; the remainder may
|
||
be alphabetic or numeric. In addition, dollar signs may be imbedded
|
||
within a variable name to improve readability. They are ignored by
|
||
PL/M. (The identifiers LINE$COUNT and LINECOUNT are interpreted
|
||
as identical names.)
|
||
|
||
The following are all reserved words, and may not be used as
|
||
identifier names:
|
||
|
||
ADDRESS DATA EOF LABEL PROCEDURE
|
||
AND DECLARE GO LITERALLY RETURN
|
||
BASED DISABLE GOTO MINUS THEN
|
||
BY DO HALT MOD TO
|
||
BYTE ELSE IF NOT WHILE
|
||
CALL ENABLE INITIAL OR XOR
|
||
CASE END INTERRUPT PLUS
|
||
|
||
PL/M Data Types
|
||
===============
|
||
There are two data types in PL/M. The data type BYTE refers to
|
||
8-bit data; ADDRESS, to 16. It is also possible to construct
|
||
arrays of either type and pointers to either type.
|
||
|
||
PL/M Constants
|
||
================
|
||
Numeric constants may be expressed as binary, octal, decimal, and
|
||
hexadecimal numbers. The radix for the number is specified by a
|
||
letter appended to the number: B for binary, O and Q for octal,
|
||
D for decimal, and H for hexadecimal. If the letter suffix is
|
||
omitted, the number is treated as decimal. Hexadecimal constants
|
||
must begin with a numeric to avoid confusion with identifier names.
|
||
As with identifiers, dollar signs may be imbedded in numeric constants
|
||
to improve readability. However a number is expressed, it must be
|
||
representable in 16 bits.
|
||
|
||
Character string constants are enclosed in apostrophes. An apostrophe
|
||
within the string must be doubled. Character strings are represented
|
||
using 7-bit ASCII codes. Character strings constants of length 1 are
|
||
treated as BYTE values; length 2 as ADDRESS values. Longer strings
|
||
are only useful with the "dot" operator.
|
||
|
||
PL/M Expressions
|
||
================
|
||
There are seven arithmetic operators in PL/M. All perform unsigned
|
||
arithmetic operations on either BYTE or ADDRESS values.
|
||
|
||
+ Binary addition operator.
|
||
- Binary subtraction operator, or unary negation.
|
||
PLUS Binary addition-with-carry operator.
|
||
MINUS Binary subtraction-with-carry operator.
|
||
* Binary multiplication operator.
|
||
/ Binary division operator.
|
||
MOD Binary remainder operator.
|
||
|
||
Multiply and divide always produce ADDRESS results. The others
|
||
produce BYTE results if both operands are BYTE values; ADDRESS,
|
||
otherwise.
|
||
|
||
There are four boolean operators in PL/M. All perform either 8-bit
|
||
or 16-bit boolean operations of their operands.
|
||
|
||
NOT Unary complement operator.
|
||
AND Binary conjunction operator.
|
||
OR Binary disjunction operator.
|
||
XOR Binary exclusive-disjunction operator.
|
||
|
||
The operators produce BYTE results if both operands are BYTE values.
|
||
If at least one is of type ADDRESS, the other is extended with
|
||
high-order zeroes if necessary, and the result is type ADDRESS.
|
||
|
||
There are six relational operators. All return a true/false result
|
||
with 0FFH representing "true" and 00H, "false".
|
||
|
||
< Binary less-than operator.
|
||
<= Binary less-than-or-equal operator.
|
||
= Binary equal operator.
|
||
>= Binary greater-than-or-equal operator.
|
||
> Binary greater-than operator.
|
||
<> Binary not-equal operator.
|
||
|
||
There is one other PL/M operator, the so-called "dot" operator. It
|
||
is a unary operator that returns the memory address of its operand.
|
||
The operator may be used in the following forms:
|
||
|
||
.variable
|
||
.constant
|
||
.(constant)
|
||
.(constant, ...)
|
||
|
||
The construction " .(08H, 'Message', 0DH) " might best be considered
|
||
as the address of a nine-element BYTE array.
|
||
|
||
Expression evaluation obeys operator precedence unless modified by
|
||
parenthesis. The following lists the operators in order of precedence:
|
||
|
||
Highest: .
|
||
* / MOD
|
||
+ - PLUS MINUS
|
||
< <= = => > <>
|
||
NOT
|
||
AND
|
||
Lowest: OR XOR
|
||
|
||
PL/M Executable Statements
|
||
==========================
|
||
Commentary.
|
||
/* Not really an executable statement, but... */
|
||
Assignment.
|
||
variable = expression ;
|
||
-or- variable, variable, ... = expression ;
|
||
|
||
Imbedded assignment. (May be used within an expression.)
|
||
(variable := expression)
|
||
|
||
Do-End. (Simple statement grouping.)
|
||
DO;
|
||
statement; ...;
|
||
END;
|
||
|
||
Do-While. (Loop while rightmost bit of expression = 1.)
|
||
DO WHILE expression;
|
||
statement; ...;
|
||
END;
|
||
|
||
Iterative Do.
|
||
DO variable = expression1 to expression2;
|
||
statement; ...;
|
||
END;
|
||
|
||
Do-Case. (Execute i-th statement, numbered from 0.)
|
||
DO CASE expression;
|
||
statement0;
|
||
statement1;
|
||
...;
|
||
END;
|
||
|
||
If-Then.
|
||
IF expression THEN statement;
|
||
|
||
If-Then-Else.
|
||
IF expression THEN statement; ELSE statement;
|
||
|
||
Go To. (GO TO and GOTO are synonomous.)
|
||
GO TO label;
|
||
-or- GO TO number;
|
||
-or- GO TO variable;
|
||
The first form causes a GOTO the statement prefixed with 'label:'.
|
||
The latter two forms cause a GOTO an absolute storage location.
|
||
|
||
Disable interrupts.
|
||
DISABLE;
|
||
|
||
Enable interrupts.
|
||
ENABLE;
|
||
|
||
PL/M Variable Declarations
|
||
==========================
|
||
Identifiers are defined with the DECLARE statement. The following
|
||
are typical forms for the DECLARE statement.
|
||
|
||
Single identifier: DECLARE identifier type;
|
||
Group of identifiers: DECLARE (identifier, ...) type;
|
||
Array: DECLARE identifier (constant) type;
|
||
Multiple: DECLARE id type, id type, ...;
|
||
|
||
Array subscripts start at 0. Thus, DECLARE A(10) BYTE; defines the
|
||
array of elements A(0)...A(9).
|
||
|
||
Declared variables may have initial values specified by including
|
||
the INITIAL attribute after the type on the DECLARE statement:
|
||
|
||
DECLARE A(10) BYTE INITIAL(10,11,12,13,14,15,16,17,18,19);
|
||
|
||
Variables declared with the INITIAL attribute are preset at program
|
||
load time. They are not reset at procedure invocation or anywhere
|
||
else. The INITIAL attribute may specify fewer values then would
|
||
be needed for the declared variables.
|
||
|
||
A DATA attribute is available for declaring storage constants. No
|
||
type or array sizes are specified; BYTE is assumed and the array
|
||
size is implicitly determined from the DATA value. The values of
|
||
identifiers declared as DATA must not be changed during program
|
||
execution.
|
||
|
||
DECLARE GREETINGS DATA ('Hello, world.');
|
||
|
||
PL/M also supports a limited macro facility. Identifiers may be
|
||
declared with the LITERALLY attribute. The literal value is
|
||
substituted in the program source text where ever the identifier is
|
||
used.
|
||
|
||
DECLARE FOREVER LITERALLY 'WHILE TRUE';
|
||
. . .
|
||
DO FOREVER;
|
||
|
||
Variables may be declared as BASED, as in
|
||
|
||
DECLARE A$PTR ADDRESS,
|
||
A BASED A$PTR BYTE;
|
||
|
||
In this example, the memory location associated with variable A is
|
||
determined by the address stored in variable A$PTR.
|
||
|
||
Labels are declared using LABEL for the type. An identifier so
|
||
declared should also appear before an executable statement, separated
|
||
from the statement by a colon. (It is often not strictly necessary
|
||
to declare all labels. An implicit DECLARE results when an otherwise
|
||
undeclared label is encountered in the program. That is,
|
||
|
||
COME$HERE: CALL PRT$MESSAGE(3);
|
||
|
||
is equivalent to
|
||
|
||
DECLARE COME$HERE LABEL;
|
||
COME$HERE: CALL PRT$MESSAGE(3);
|
||
|
||
However, due to scope rules, a earlier reference to the label (in a
|
||
GOTO statement) may be flagged in error, because the implicit DECLARE
|
||
is physically latter in the program.
|
||
|
||
PL/M Procedure Declarations
|
||
===========================
|
||
Procedures must be defined before they are used. This declaration
|
||
form is:
|
||
|
||
identifier: PROCEDURE (arg, ...) type;
|
||
statement; ...;
|
||
END identifier;
|
||
|
||
The 'identifier' (which appears in two places) specifies the name for
|
||
the procedure. If no result is returned, the 'type' is omitted from
|
||
the PROCEDURE statement.
|
||
|
||
Return from a procedure is implicit after the last statement of the
|
||
procedure, although no value is returned in this case. Return may be
|
||
explicitly specified with the RETURN statement:
|
||
|
||
No value: RETURN ;
|
||
Value: RETURN expression ;
|
||
|
||
Procedures may be declared with the special type INTERRUPT followed
|
||
by a number in the range 0 through 7. Such a procedure will be used
|
||
as an interrupt handler for the corresponding RST instruction.
|
||
Interrupts are re-enabled on return from an interrupt procedure.
|
||
|
||
Procedures may not be recursive. Procedures are invoked either with
|
||
the CALL statement, or within an expression.
|
||
|
||
Stand-alone: CALL identifier (arg, ...);
|
||
Within expressions: identifier (arg, ...)
|
||
|
||
Built-in Procedures
|
||
===================
|
||
INPUT(number)
|
||
Returns a BYTE value from the I/O port specified by 'number'.
|
||
|
||
OUTPUT(number) = expression;
|
||
Sends the BYTE value of 'expression' to the I/O port specified
|
||
by 'number'.
|
||
|
||
LENGTH(identifier)
|
||
Returns the number of elements in the array 'identifier'.
|
||
|
||
LAST(identifier)
|
||
Returns the highest subscript for array 'identifier'. Note that
|
||
LAST = LENGTH - 1.
|
||
|
||
LOW(expression)
|
||
Returns the low-order byte of 'expression'.
|
||
|
||
HIGH(expression)
|
||
Returns the high-order byte of 'expression'.
|
||
|
||
DOUBLE(expression)
|
||
Returns an ADDRESS value equivalent to 'expression'. High-order
|
||
zeroes are used to pad BYTE expressions.
|
||
|
||
ROL(expr1, expr2) and ROR(expr1, expr2)
|
||
Returns the value of 'expr1' rotated left/right the number of bits
|
||
specified by 'expr2'. Both expressions must be BYTE values. The
|
||
value of 'expr2' must not be zero.
|
||
|
||
SCL(expr1, expr2) and SCR(expr1, expr2)
|
||
Returns the value of 'expr1' rotated left/right the number of bits
|
||
specified by 'expr2'. The carry flag participates in the rotate.
|
||
'expr2' must be a BYTE value; 'expr1' may be BYTE or ADDRESS. The
|
||
value returned is of the same type as 'expr1'. The value of
|
||
'expr2' must not be zero.
|
||
|
||
SHL(expr1, expr2) and SHR(expr1, expr2)
|
||
Returns the value of 'expr1' shifted left/right the number of bits
|
||
specified by 'expr2'. The last bit shifted out ends up in the
|
||
carry flag. 'expr2' must be a BYTE value; 'expr1' may be BYTE or
|
||
ADDRESS. The value returned is of the same type as 'expr1'. The
|
||
value of 'expr2' must not be zero.
|
||
|
||
CALL TIME(expression)
|
||
The expression is evaluated as a BYTE value. The TIME procedure
|
||
delays 100 microseconds times the value. (Timing is based on
|
||
instruction execution times for the standard i8080 cpu.)
|
||
|
||
DEC(expr1 + expr2) and DEC(expr1 PLUS expr2)
|
||
The two expressions must be unsubscripted variables, constants,
|
||
or expressions that represent BCD values. The DEC function does
|
||
the necessary decimal adjustment to produce the BCD result from
|
||
the addition.
|
||
|
||
Pre-defined Variables
|
||
=====================
|
||
CARRY, ZERO, SIGN, PARITY
|
||
The values of these variables reflect the current values of the
|
||
cpu flags.
|
||
|
||
MEMORY
|
||
The MEMORY variable is assigned the to the first memory location
|
||
following the PL/M program. It is useful for determining where
|
||
free memory begins.
|
||
|
||
STACKPTR
|
||
The STACKPTR variable's value reflects the current value of the
|
||
SP register. The variable may be assigned a new value to alter
|
||
the stack register.
|
||
|