The PLµS programming language
It is widely understood that well-structured programs are easier to understand, easier to debug, and easier to maintain. Structured programs can be written in any programming language, including assembly language. But assembly does not offer many features to assist the programmer. High-level machine-independent programming languages do. They have niceties such as loops and other control structures, data structures, and offer modularity. But these features come with an unacceptable trade-off: a substantial run-time memory and execution overhead. For a small microprocessor like the 2650, an intermediate-level machine-dependent language might give just the right balance between well-structuredness and efficiency. High-level features for readability and maintainability, but close enough to the hardware to allow for efficient execution.
The PLµS programming language was Signetics’ attempt at such a high-level machine-dependent programming language. PlµS was created on request of Signetics by Gary Kildall (aka “the father of CP/M“), as a 2650-variant of the PL/M language that Kildall created for Intel.
Relation to PL/M
The original documentation or language description of PLµS is no longer available, but there is still a lot of documentation available for PL/M. See the sidebar for a number of links. PL/M was first developed for the 8008 processor, but as Intel released newer processors the variants of PL/M evolved: PL/M-80 for the 8080, PL/M-86 for the 8086, PL/M-286 for the 80286, etc. This often raises uncertainty when documents refer to “PL/M” without specifying which variant of PL/M.
Differences
One interesting paper is “A Survey of Microprocessor Languages” (S. Crespi-Reghizzi, P. Corti, and A. Dapra, 1980, IEEE Computer). This paper compares PLµS to PL/M-80 and confirms that both are very similar, like dialects, and have been designed by the same person (i.e. Kildall). But it also lists features that are omitted from PLµS:
- In PLµS all memory is statically allocated. This may be related to the the fact that reentrant procedures are not used.
- It appears that PLµS and PL/M treat the character type differently. In PL/M-80 characters are
BYTE
s, whereas PLµS may have a separate type for characters. (The paper is not specific). - It appears that PLµS does not allow label declarations. The ability to declare a label is explicitly mentioned with PL/M-80 but is omitted with PLµS.
Then again, PLµS offers some features that are not part of PL/M-80:
- PLµS has signed bytes and signed words whereas PL/M only has unsigned bytes and words. It is not described how signed variables are declared in PLµS. PL/M-86 has a signed two-byte variable type
INTEGER
but no single-byte signed type. - PLµS contains a large set of directives for conditional compilation, and performs most operations involving constants at compile-time. For example, the
COMPILE-CASE
statement is like theCASE
statement but selects one of the statements for compilation, based on the value of an expression which must evaluate to a compile-time constant. - In PL/M-80 the increment in iterative
DO
loops must be a positive number. This limitation is not present in PLµS; the increment can be negative (but presumable should still be non-zero). - PLµS has a
DO UNTIL expression
loop.
Some differences are because PLµS is based on PL/M for the 8008, not the later version PL/M-80:
- PLµS does not have
INTERRUPT
procedures. - PLµS does not support the
STRUCTURE
type. Therefore, the component type of arrays should be a simple data type as well. - Recursive calls of procedures are not permitted in PLµS. The keyword
REENTRANT
apparently is not used. - In PLµS procedures cannot be called by the value of their first address. (The
GO TO
statement can jump to a specific memory address).
The paper also states that PLµS will convert the types of actual parameters to those of their corresponding formal parameter. However, the PL/M-80 manual mentions that on CALL
automatic type conversions are performed, so presumable this is an error in the paper.
Info from Signetics
Although the language definition manual has been lost, other documentation by Signetics mention PLµS and some of its features. For example the “Buyers & engineers guide, memories and microprocessors” (Philips/Signetics, 1978):
- Claims that PLµS contains all machine-independent features of PL/M as a subset. This may be correct when referring to PL/M for the 8008, but PL/M-80 is clearly not a subset of PLµS.
- PLµS can include assembly language inline.
- Does not mention the “signed” variants of
BYTE
andADDRESS
. It says that The language handles two kinds of data, its two basic “Data Types”: Byte and Address. PerhapsBYTE
andADDRESS
are signed in PLµS by default?
Introducing PL/2650
Based on PL/M, and on the documented differences that we found, we can attempt to recreate the language reference for PLµS. Some PLµS- and 2650-specific features have to be be added, drawing inspiration from the 8080-specific language features as described in Intel’s documentation. To make it clear that the resulting language is not PLµS exactly I will call it PL/2650 for now.
Handling differences between PL/M and PLµS
PLµS has data types for signed one-byte and two-byte values. PL/M-86 introduces INTEGER
as a two-byte signed value, but does not offer a one-byte signed type. Either we make BYTE
and ADDRESS
signed by default in PL/2650, or we introduce new syntax SIGNED BYTE
and SIGNED ADDRESS
.
It is not specified what directives for conditional compilation exist, but with COMPILE-CASE
it seems logical that a COMPILE-IF .. COMPILE-THEN .. COMPILE-ELSE
exists. As in COMPILE-CASE
, the condition in COMPILE-IF
should evaluate to a compile-time constant.
The DO .. UNTIL expression
loop is presumable identical to DO .. WHILE NOT (expression)
.
2650-specific functions
Features that are specific to the 8080 processor are described in Chapter 12 of the PL/M-80 Programming Manual.
2650-specific features in PL/2650 concern I/O to ports C and D, and the program status word bits. Functions for (extended) I/O and for adjusting BCD-encoding can probably be adopted without modification. Binding of PL/2650 to assembler routines is also different from PL/M, simply because the 2650 has different registers than the 8080.
I/O ports
Built-in procedure INPUT
takes a byte argument and returns a byte value. In PL/2650 this can refer to extended I/O. Built-in array OUTPUT
can only be assigned to; assignment is used to write to an extended output port in PL/2650.
In analogy, PL/2650 uses the built-in bytes INPUT$C
and INPUT$D
, to read from port C and D respectively. Assignments to built-in bytes OUTPUT$C
and OUTPUT$D
result in writes to port C and D. Like OUTPUT
, variables OUTPUT$C
and OUTPUT$D
cannot appear anywhere else than at the left-hand side of an assignment.
Program Status Word
PL/M-80 defines the hardware flags CARRY
, ZERO
, SIGN
and PARITY
. Of these only CARRY
has a direct equivalent on the 2650. The 2650 also uses hardware flags CC1
, CC0
, OVERFLOW
, IDC
, RS
, SENSE
and FLAG
; the 2650B adds UF1
and UF2
.
Flags CC1
and CC0
can be used to set, clear and test individual bits in the Condition Code. Since the 2650 uses the two CC-bits in combination, ‘virtual’ hardware flags are defined as well. EQ
, GT
and LT
can be used to set, clear and test the two Condition Code bits to 00B
, 01B
and 10B
respectively. Z
, P
and N
are functionally identical to EQ
, GT
, and LT
but provide an alternative notation that may be more descriptive in certain situations. Flags RS
, OVF
, IDC
and CARRY
can be used to set, clear and test the Register Select, Overflow, Interdigit Carry, and Carry bits. (Perhaps these flags should be prefixed by PSW$
, otherwise identifiers Z, P, etc become reserved words. So PSW$Z
etc. A STRUCTURE
called PSW
would have been neat, but that requires that structures are added to PL/2650.)
Some PSW bits are absent from this definition.
- Interrupt Inhibit
II
relates to interrupt handling, which PLµS does not support. Any interrupt routines will need to be covered by (inline) assembly routines. - The stackpointer bits need not be manipulated by programs, and are omitted.
- The With Carry flag
WC
is always disabled, and will be enabled automatically for operations that
require it (PLUS
,MINUS
, and the shift/rotate operations that explicitly use the Carry bit). - The Compare bit
COM
is under control of the compiler, and will be set or cleared depending on whether signed or unsigned variables are used.
Memory and STACKPTR
The MEMORY
array starts at the first unused address after the program, as in PL/M. As in PL/M there is no indication of what a safe or valid upper limit is to this array.
The meaning of STACKPTR
in PL/2650 is to be decided. The stack will have to be emulated (unlike the 8080 where it is built-in). The stack and MEMORY
compete for the same memory, with a fixed and limited amount being allocated to the stack. However, since procedures cannot be re-entrant in PLµS it is not certain whether STACKPTR
is necessary at all.
Start address
A program may optionally contain a numerical label (which otherwise is not allowed, as identifiers must start with a letter), indicating the starting address of the program. This is not described in the Intel PL/M-80 Programming Manual, but is described in the MCS-8 manual (section 14.1) and is referred to in the PL/M Compiler Operators Manual (page 21). The $H
compiler control can be used to set the start address as well.
Interfacing to assembler code
The first parameters to procedures can be passed in registers, as it is done in PL/M. Exactly how this can be done is still not certain. Also, the way to express inline assembly is to be decided.
Next steps?
I am hoping to collect more information on PLµS before finalizing the language definition for PL/2650. I expect that writing a PL/2650 will be quite a job, and although this seems like an interesting project its priority is low.
Meanwhile, as always, I appreciate feedback and suggestions.
Intel documentation
A Guide to PL/M programming, Intel, 1973. Processor specific details for 8008. Language is claimed to only require a recompile to make it suitable for 8080.
PL/M-80 Programming Manual, Intel, 1976. Processor specific details for 8080.
ISIS-II PL/M-80 Compiler Operator’s Manual, Intel document number 98-300. Not found yet; according to MANX no copies are online.
8080 PL/M Compiler Opertors Manual, revision A, Intel, 1975. A cross-compiler consisting of two Fortran programs: PLM81 and PLM82.
ISIS-II PL/M-86 Compiler Operator’s Manual, Intel, 1978. Annex E describes the differences between PL/M-80 and PL/M-86.
PL/M-86 User’s Guide, rev 002, Intel, Nov 1981. For iAPX 86 and iAPX 88 microcomputer systems.
PL/M-51 User’s Guide, Intel, 1983. Compiler for the MCS-51 family of embedded controllers.
Other documentation
A guide to PL/M programming for microcomputer applications, D. McCracken, Addison-Wesley, 1978.