There are many commonly-used PDP-8 assemblers, several of which we ship with the PiDP-8/I software distribution; there are more available elsewhere. How does a programmer discriminate among them, other than to carefully read each one's manual, then spend several months writing code in it to develop a feel for what it is like? They cannot all be equal, else they'd be interchangeable and you'd just pick one based on what was available. One cannot be clearly better for all things, else everyone would just use that.
This article is a preliminary survey of these assemblers with an eye toward listing the key distinctions among them. It is modeled on a birder's field guide: having read through this document, a reader should be able to recognize which assembler(s) are likely to be able to process a given piece of assembly code by recognizing uses of key features of the assemblers we describe here.
Secondarily, we hope to provide enough information that a programmer beginning a PDP-8 assembly language project be able to make a sensible assembler selection without getting bogged down in minutiae. That ambition likely exceeds this document's current scope, but we strive anyway.
A distant third goal is historical: we wish to document the evolution of the major PDP-8 assemblers in enough detail that the reader can anchor each covered assembler in its historical context. Although this history is of inherent interest, we do this primarily to make it easier for the reader to keep these assemblers and their interrelationships straight. An evolutionary narrative makes this easier than would discussing each assembler as if it were created in isolation.
When multiple versions of a given assembler are available, our commentary applies to the version currently in the PiDP-8/I software distribution, if present, or the latest available version of the assembler if it is hosted externally. We tend to prefer earlier manuals, however, interested as we are here in history.
This survey does not include every PDP-8 assembler, on purpose. This is not a comprehensive survey, it is not a genealogy project, and it is not an advocacy platform. In addition to meeting the goals laid out in the previous section, an assembler must meet all of these criteria to be covered:
It must be readily available online.
It must offer at least one of the following capabilities to the end user:
- Be the back end assembler for some other language which is itself important.
- Be required to build an important body of code which is readily available online.
- Be the best available assembler for its primary platform, or at least be an important secondary option.
It must run on the PiDP-8/I, either under Raspbian Linux or under one of the PDP-8 OSes we distribute.
That list is not intended to be normative or complete, just informative: if an assembler fails to meet all of those criteria, that is likely why it is not listed here.
As a rule, we discuss only the latest available version of any given assembler. Our MACREL coverage is for MACREL v2, for example, not MACREL v1, even though the latter is more readily found online. We've made an exception for PAL-D, covering both the 4K and 8K versions because they were contemporaneous, serving different segments of the PDP-8 market.
The author is not an expert in this topic, though he has occasionally consulted with experts. The claims in this document are checked against manuals, published example code, and sometimes against running implementations. However, do not expect it to be complete or comprehensive.
Keep the criteria above in mind when contributing.
|PDF, 790 kB
We may presume from the name that PAL-III has at least two predecessors. I was able to find a reference to DEC product number 5-1-S, the Program Assembly Language for the PDP-5 in the PDP-5 program catalog from December 1964; we may reasonably call this assembler PAL-I. That catalog also says that the replacement for PDP-5 PAL is an early version of PAL-III for the PDP-8. This makes sense, because the PDP-8 directly replaced the PDP-5 in DEC's product line, being upward compatible with it.
I have yet to come across a reference to anything called "PAL-II." Perhaps it went the way of Angular 3, Winamp 4, Netscape 5, PHP 6, MySQL 7, QuickTime 8, and Windows 9.
The introduction date above is the publication date of the earliest PAL-III manual I have found, but clearly PAL's ancestry dates back to at least December 1964. An early PDP-5 brochure I found from March 1964 speaks of a "Symbolic Assembler" rather than PAL; is that just marketing-speak for "PAL," or does PAL first date to somewhere in that range?
The PAL-III assembler shipped on punched paper tape as part of the grandiosely-named "PDP-8 Assembly System." This amounted to an assembler, an editor, a debugger, and a loader, each a separate paper tape. The programmer would first toggle the RIM loader into the PDP-8's front panel, then use that to load the BIN loader from a fifth paper tape, separate from the PDP-8 Assembly System, then run each of these tapes through the paper tape reader repeatedly — reusing the still-in-core BIN loader each time — in order to iterate his way toward a working program.
The PAL-III assembler tape required at least two passes through the tape reader in order to produce a computer-readable BIN format output tape, plus an optional third pass if you also wanted a human-readable listing on the teletype.
If you look at pictures of PDP-8 computers, you can often see a tray with narrow slots in it, each meant to hold one of these key paper tapes, as they were needed near at hand when using a paper-tape based PDP-8. There is a good picture of a blue one on the cover of the OS/8 Handbook, 1974 ed.
PAL-III can be considered the baseline assembler for a PDP-8, since for roughly its first decade, PDP-8s sold for interactive use came with a Teletype Model 33 ASR with built-in paper tape reader and punch, which meant the ability to read paper tapes was a baseline feature for interactively-used PDP-8s. (Contrast headless embedded PDP-8s, a very common use for the PDP-8 prior to the introduction of the microprocessor.)
More importantly for our purposes here, most of the other assemblers surveyed here share PAL-III's basic syntax. This doubtless follows on from the prior point, since it meant PAL-III had the first-mover advantage.
A brief summary of the feature set of PAL-III:
- Full support of the PDP-8 instruction set:
- All basic processor instructions and several microcoded combinations (
SPA, etc.) predefined
- Many peripheral IOT instructions predefined:
- Zero-page addressing
- Indirect addressing
- All basic processor instructions and several microcoded combinations (
FIXMRIpseudo-ops to augment or redefine the predefined instruction set
PAUSEassembly output, giving the user time to do manual things while the assembler waits
OCTALpseudo-ops for radix selection
FIELDpseudo-op to select the core memory field
We give this list not to try to replace the PAL-III manual, but instead to allow searching this document for language features. You may assume that assemblers listed below also support these listed features, especially within the PAL genealogical line; we call out the exceptions below.
|PDF, 1.7 MB
MACRO-8 was another paper tape assembler for the PDP-8. Its eponymous advantage over PAL-III is that it added macros, a very useful feature in assembly language programming as it reduces a lot of the tedium of writing such programs.
MACRO-8 is based on the PAL-III language, but it added much more than just macros:
DEFINEmacro definition system
- automatic off-page link generation
- literals in the current page via
(NN)syntax or in page zero via
[NN]; closing paren/bracket optional
- more operators in expressions:
!for Boolean OR (the ASR-33 terminal character set did not include the ¦ character)
&for Boolean AND
- single-character ASCII constants:
"A"; closing quote optional
- other new pseudo-ops:
DUBL: define double-precision integer constant
FLTG: define double-precision floating-point constant
PAGE: [re]set the location counter to the top of the given page
TEXT: convert a literal string in the program text to 6-bit packed ASCII in the binary output
DEFINE feature is clearly this assembler's marquee feature, but it is the rest of the list that should open your eyes: all of these features except for
FLTG were later adopted as-is into the PAL family.
MACRO-8 dropped the
FIXMRI pseudo-op relative to PAL-III. One manual I examined showed an example that could only be done using
FIXMRI under PAL-III, by which I infer that MACRO-8 simply doesn't need the hint from the user: memory reference instructions can be detected as part of regular symbol table manipulations.
Historical vignette: Where the earlier PDP-8 assembler manuals refer to the new ASCII character constant feature, they actually either refer to "USA SCII" or to "ANSCII", those being the original names of ASCII: the United States of America Standard Code for Information Interchange; or the American National Standard Code for Information Interchange. You may also see "US-ASCII" in some places, being another way of writing "USA SCII".
|PDF, 1.9 MB
PAL-D is a descendant of PAL-III, originally appearing as part of the PDP-8 Disk Monitor System, one of OS/8's predecessors. It would later reappear under TSS/8.
Wikipedia claims that the first version of the Disk Monitor was published in late 1967, but the earliest PAL-D manual I've been able to find has April 1968 as the date of its first edition.
PAL-D came in two forms, the 4K and 8K versions, referring to the minimum amount of core memory each required. Note that the 4K version could assemble for larger machines; it has the
FIELD pseudo-op, for example, which is of no use unless your assembled program would run in at least 8K of core.
4K PAL-D added only one new feature to the PDP-8 assembler family: the
XLIST pseudo-op, which lets the programmer stop and then re-start the assembly listing in the optional third pass.
4K PAL-D is more notable for the features it brought into the PAL family from MACRO-8:
- off-page link generation
- Boolean operators in expressions
8K PAL-D added several more features relative to the 4K version:
- ability to run in 8K or 12K of core, allowing assembly of larger programs
- more pseudo-operations:
EJECT: emit a form feed in the listing output
IFZERO: conditional assembly tests; affected statements in angle brackets
ENPUNCH: stop and restart assembled machine code output
ZBLOCK: reserve memory, setting initial values to zero
Note that neither version of PAL-D brought over the
FLTG pseudo-ops from MACRO-8.
Notice also that the negated forms of the conditional assembly operations did not appear until later. The first reference I've been able to find for
IFNDEF is in connection with PAL8.
We find evidence for a complicated development history in the
XLIST pseudo-ops. They do much the same thing, only for different passes of the assembler, yet the form of the ops differ. If this assembler was created by a single mind in a single time and place, or if it were created by a standards committee with a mandate to simplify and unify, you would expect these two sets of pseudo-ops to have similar names and forms, either
XPUNCH taking an argument or a
ENLIST pair. We can infer different minds behind the 4K and 8K versions of PAL-D.
PUNCH op names also suggest that the operation is mainly useful for paper tape output, still an important I/O device when PAL-D was new. We can find it mentioned in the PAL8 section of the OS/8 Handbook (1974 ed.), but it was airbrushed out of history by the 1979 edition for OS/78, suggesting that the purpose of these pseudo-ops became effectively redundant after the bulk of the market moved to disk-based PDP-8 systems such as the DECstation 78, a microcontroller-based PDP-8 merged with a VT52 video terminal, which effectively replaced the teletype + paper tape reader/punch most often used with earlier PDP-8 systems. (Thus the renaming of "OS/8" to "OS/78," by the way.)
Like MACRO-8, PAL-D does not have the
|PDF, 38 MB
|part of OS/8
OS/8 was the primary programming system from DEC for the PDP-8 in its later years. It included several different assemblers, all documented in the OS/8 handbook. The 1974 edition is linked above. You may also find the later OS/78 Handbook from 1979 interesting for comparison purposes.
The introduction date is that of OS/8, but OS/8 has a complicated development history that stretches back to 1966 or so. Some of the following assemblers predate OS/8; where the dates for them are known, they are called out below. For those with no additional date information, it is possible that it was first introduced after OS/8 but before 1974, the date of the manual linked above, which talks about all of these assemblers.
The earliest attestation to the PAL8 assembler I've been able to find is in the May 1970 printing of Programming Languages, the second in a two-volume set on programming PDP-8 family computers. (The first volume being Introduction to Programming.) On page 14-7 in the section on 8K PAL-D, it gives a Disk Monitor command for saving the in-core copy of 8K PAL-D as "PAL8". It is therefore unsurprising that the OS/8 version of PAL8 is morphologically more similar to PAL-D than to PAL-III.
The earliest reference to PAL8 as a named product of DEC is in the PS/8 8K Programming System User's Guide from October 1970, that product being the immediate predecessor of OS/8.
PAL8 understands the same basic language as PAL-D but generally has more features, most especially related to running under OS/8.
I consider PAL8 the default assembler for OS/8 users. If none of the information below guides you to one of the other assemblers, you should probably start with PAL8. If you have a piece of assembly code that is meant to be assembled under OS/8, and you have no evidence that is for any other assembler, it's probably meant to be assembled by PAL8.
PAL8 has many features not present in 8K PAL-D:
- assembly options set via OS/8 CCL flags rather than via front-panel switches
- output option for producing input to CREF
- more operators in expressions:
^for 12-bit unsigned multiplication (
*was already taken for setting the location counter)
%for 12-bit unsigned division (
/was already taken as the comment start character)
FIXMRIpseudo-op is back
EJECTpseudo-op extended to allow the page header to be changed for the next and following pages
- new pseudo-operations:
TEXTfor passing arguments to OS/8 service routines
DTORG: set DECtape block number in output for the Typeset-8 computerized typesetting system (photo)
IFNZROnegated forms of the conditional assembly tests
RELOC: assemble code for relocation after loading
The restoration of the
FIXMRI pseudo-op is curious. It is not clear from the manuals whether its use is again required for redefining memory reference instructions (MRI) after an
EXPUNGE call or if it is merely for compatibility with certain existing PAL-III programs. (TODO: Try it and see.)
The existence of the
RELOC pseudo-op should not be taken as a sign that PAL8 is a relocatable assembler. It simply allows code to be assembled starting at one fixed address which is intended to be run at a different fixed address. A proper relocatable assembler generally tries to hide the fixed addresses it uses when assembling your program; compare SABR, for example, which produces output that cannot be run directly, but which must be processed by a relocating loader (
LOADER.SV) to fix up the addresses to their final execution values.
PAL-III has one feature not implemented in PAL8: the ability to get a brief listing of the undefined symbols in a program. The information is instead presented inline in the listing output, not grouped together into a single place, which can make refinement of an in-development program tedious as you need to comb information about undefined symbols out from among all the other output.
RALF uses approximately the same statement syntax as the PAL family, but it is a very different assembler by nature. We can divide its differences into several groups.
Floating Point Processor Support
RALF is not only an assembler for the PDP-8 processor, it is also an assembler for the FPP12 Floating Point Processor (FPP) peripheral.
RALF is the back-end assembler for the OS/8 FORTRAN IV compiler, which delegates all of the FPP handling to RALF, but at program load time,
FRTS checks for the existence of an FPP and switches to a software FPP simulator if there is no FPP present. (
FRTS does the same for the EAE, by the way.)
Although the FPP12 was introduced with the PDP-12, it is not restricted to use with the PDP-12: it also works with all of the other PDP-8 family computers contemporaneous with and preceding it, going back to the original PDP-8. This is possible because the FPP is a bus peripheral rather than a feature of the CPU proper. DEC justified this in their documentation, pointing out that it means that a site can upgrade their existing processors with an FPP rather than buy a whole new machine with integrated FPP features when they find that software FP is taking too much time to run.
There was also a follow-on peripheral for the PDP-8/a called the FPP8-A, as well as a later variant called the FPP12A, both of which are instruction-compatible with the original FPP12. The FPP features of RALF allow you to intermix FPP instructions with PDP-8 instructions just as if the FPP were part of the PDP-8 CPU, rather than being a very different external coprocessor.
Here is a summary of the FPP-related features of RALF:
- More instructions and pseudo-ops:
- Conditional jumps:
- FPP to PDP-8 jumps:
- Mark module as requiring double-precision hardware:
- Pointer moves:
- Processor operations:
- Register manipulation:
- Set single-word addressing mode base address:
- Use 15-bit (double-word) addresses directly in FPP instructions, rather than the PDP-8's memory model
If you see any of those instructions in a PDP-8 assembly language program, it's a pretty good indicator that it's meant to be assembled by RALF or FLAP.
RALF generates relocatable output code in
*.RL files rather than absolute-addressed output, which means you cannot simply load its output into core and execute it directly. You must use the OS/8 FORTRAN IV loader (
LOAD.SV) to load one or more
*.RL files into core memory, link them to any external libraries, convert relative addresses to fixed addresses, and write out a loader image (
*.LD) which can then be loaded an run by the OS/8 FORTRAN IV Run Time System,
The compensation for this complicated scheme is that
FRTS.SV provide a powerful overlay and linkage loading scheme which allows for programs up to about 300 kWords in size, nearly 10× the maximum core memory size in a standard PDP-8 family computer. It does this by loading code from disk as needed. This scheme is made possible by the relocatable output code from RALF.
(Do not confuse
LOAD.SV, the OS/8 FORTRAN IV loader — used by both RALF and F4 — with
LOADER.SV, the simpler "linking loader" used by the OS/8 FORTRAN II compiler (
FORT.SV) and by SABR. There's a second cause for confusion: both loaders use
*.RL as their default input file name extension, so RALF, F4, FORT, and SABR all output files with that extension.)
RALF also has many other improvements over late-generation PAL family assemblers such as PAL8 which are not directly tied to driving the FPP or to relocatable code:
- Multiplication is
^; this is possible because RALF offers the
ORGpseudo-op to set the location counter, where PAL family assemblers use
- Division is
%, achieved by requiring whitespace before
/if used to start a comment and disallowing spaces in expressions
- Multiplication is
- Many new and changed pseudo-ops:
ADDR: define address constant
F: define floating-point constants
IFRALFconditional assembly pseudo-ops
IFDEFpseudo-op, having a superset of its functionality
LISTON: stop and start listing output rather than the PAL family's
REPEAT: assemble the following line multiple times
SECT8pseudo-ops to support FORTRAN IV code
Some may argue about my grouping of the expression changes here rather than under the Arbitrary Differences section below. I made this choice because the change was necessary to allow an improvement.
There are restrictions in RALF relative to late-generation PAL family assemblers that are justifiable on the grounds that they follow from the requirement that the output code be relocatable:
It does not understand the
PAGEpseudo-op: the PAL form of this feature — where the page number is given as an argument to the pseudo-op — inherently goes against the nature of relocatable output. The inability to accept the argument-less version understood by SABR is harder to justify.
It does not support current-page literals —
(42)— since allowing it would complicate relocation.
There are additional differences in RALF relative to the PAL family assemblers that seem entirely arbitrary to me:
Indirect addressing is done differently:
TAD I A / PAL syntax TAD% A / RALF syntax
The programmer must tell the assembler when zero-page addressing is needed:
TAD A / PAL syntax, implicit Z flag based on known location of A TAD Z A / PAL lets you be explicit if you want; space is not optional TADZ A / RALF syntax: RALF needs to be told; no space can be given
Its expression syntax has no "and" operator,
It does not support zero-page literals:
This restriction does not seem to have a good justification, even in relocatable assembler output, since the nature of the feature at both at the assembly and machine code levels is that the memory reference is inherently absolute. Thus, generation of a zero-page literal cannot affect the ability of the loader to relocate the generated code.
RALF was based on a simpler assembler called FLAP, which generates absolute-addressed code, just as PAL8 does. This section will simply describe the differences in FLAP relative to RALF. These differences aside, FLAP shares the feature set of RALF.
The primary advantage FLAP has over RALF is that, because it is difficult to ascribe meaning to the "page" concept in relocatable assembler output, RALF doesn't support the
PAGE pseudo-op, while FLAP does. FLAP also supports the PAL family's zero-page and current-page literal syntaxes, while RALF does not.
FLAP has one pseudo-op that RALF does not,
S for defining a single-word integer constant.
Because FLAP output is absolute-addressed, it writes
*.BN files as output rather than
*.RL. These are linked and loaded by the OS/8 absolute loader,
ABSLDR.SV, rather than by the relocating loader used by RALF,
LOAD.SV. You can link and run several files directly this way, or you can just load them into core and
SAVE them to a
*.SV file for later use by the OS/8
R command. This is both simpler and less powerful than the RALF/FRTS dynamic overlay scheme: FLAP programs cannot be any larger than core memory unless you, the programmer, do the manual work to create your own overlay swapping scheme.
FLAP.SV is currently not provided on the PiDP-8/I project's OS/8 disk packs. It is not present on the OS/8 source media we're using, but we don't know if this is because it was removed from OS/8 by DEC or if we simply missed the FLAP source media when curating the input media we use for building our OS/8 disk packs. When we figure that out, I'll update this article.
There is a
FLAP.SAV program on the PiDP-8/I project's TSS/8 boot media, but we have not yet spent the time to figure out how to make it work. None of the TSS/8 manuals we have access to talk about FLAP, so this is not likely to be a quick investigation.
By the way, you may find pages online that claim that FLAP was derived from RALF, rather than the other way around. I'm basing my claim on what DEC's own documentation says: "RALF, an extension of FLAP..." This quote was found in two different OS/8 manuals published about 5 years apart.
As RALF is to OS/8's FORTRAN IV compiler, so the Symbolic Assembler for Binary Relocatable programs is to OS/8's FORTRAN II compiler.
SABR does not have any tie to the FPP, unlike RALF and FLAP.
The most notable feature of SABR is that the programmer normally writes SABR code as if using a flat memory model machine, ceding all control over literal placement and of page/field boundary placement to the assembler. This feature — called automatic paging — frees the programmer from having to deal with the strange PDP-8 memory model, but it also means she is dependent upon the assembler to make smart decisions about all of this, even while SABR must itself run within those same constraints. This makes writing SABR easier than for most other PDP-8 assemblers, but because you can't get a whole lot of optimization smarts into a 6 kWord program, the output code tends to be less efficient than hand-tuned code for other assemblers.
You can see this design decision in several language differences relative to PAL-III or PAL8:
FIELDpseudo-op; not needed, given relocatable output
PAGEpseudo-op takes no argument: it simply forces the assembler to go to the next page
Off-page indirection is allowed; the assembler will generate instructions to jump between pages as needed
No square bracket syntax for placing literals on page zero
Several new pseudo-ops to get around the fallout of all this programmer freedom:
ABSYM: define a symbolic name for an absolute core memory location
CPAGE: reserve N words of core on the current page if space is available, else next page
EAP: leave and re-enter automatic paging mode
SKPDF: define custom op-codes;
INCnon-skip version of
REORG: similar to
*feature of PAL, except that it's forced to the top of the page
Arithmetic expressions banned in operands; simple
N+1case replaced by the
You may be surprised to see the
SKPDF pseudo-ops grouped among these consequences of the way SABR works as compared to the PAL type assemblers. This is because the PAL way of defining custom opcodes (e.g.
DVI=7407) assumes the programmer knows what she is doing with regard to whether the opcode can cause the next instruction to be skipped. Since the SABR programmer generally doesn't know where the page boundaries are, that means she cannot predict what certain instructions will look like in the final machine code, and thus whether a skip will do what she wants it to. SABR therefore provides two different ways to define custom opcodes, one for each case, which allows the programmer to clue the assembler into the correct output.
SABR does have some special accommodations for page zero. The
ABSYM directive can place values on page zero, and the use of small literal constants in instructions like an indirect
TAD is understood to refer to page zero:
ABSYM AINC0 K10 / define name for auto-increment register 10 octal
........ / load a core address into AC somehow
TAD I AINC0 / pseudo-C: ac = *ainc0++;
SABR has a bunch of pseudo-operators to support SABR's role as the back end of OS/8 FORTRAN II:
ARG: define address/argument value pairs for calling FORTRAN subroutines
CALL: call external subroutine
COMMN: set aside storage space in field 1, which OS/8 FORTRAN II uses for
DUMMY: used in the calling convention for FORTRAN subroutines
END: mark end of program or subprogram; replaces meaning of
ENTRY: mark subprogram entry point
FORTR: assemble FORTRAN tape
RETRN: return from external subroutine
If you see any of the above pseudo-ops in a bit of code that otherwise adheres to the PAL-III base syntax, it's probably SABR code.
More features exist in SABR which are not consequent to any of the above design constraints:
ACL: address sub-words in a multi-word value
Dprefix on numeric constants cause decimal interpretation where
OCTALis otherwise in effect
Kprefix for octal-in-decimal-context flip case
IF: conditionally skip assembling some number of the following instructions
Finally, there are some things which are different or missing in SABR as compared to PAL8:
BLOCK: same as
ZBLOCKin PAL8 and PAL-D
IFnot as flexible as
- Missing pseudo-ops:
FILENAME: not needed, call thru FORTRAN II library instead of direct to OS/8 USR
RELOC: not needed, SABR output is relocatable by default
A programmer may use SABR one of three ways:
- Implicitly as the back-end of the OS/8 FORTRAN II compiler
- Explicitly via inline assembly code in a FORTRAN II program
- Directly as a standalone assembler.
The third option still depends upon FORTRAN II because SABR writes its
*.RL output files with the assumption that they will be linked to the FORTRAN II runtime and libraries by the OS/8
LOADER program, so the generated code makes use of those facilities. This means SABR programs can always call any FORTRAN II library routine without special effort, since it is always going to be linked to it by
Ian Schofield's CC8 compiler compiler operates like the OS/8 FORTRAN II compiler, emitting SABR output and depending upon the FORTRAN II library and runtime. Inline assembly via
#asm is sent as-is to SABR.
|1977 (v1), 1979 (v2)
|text, 384 kB
|DECtape for OS/8
Although this is technically another OS/8 assembler, its late introduction, separate documentation, and separate distribution from OS/8 proper require that we consider it separately.
Aside from MACRO-8, none of the assemblers above support macros, a very helpful feature in assembly language programming. MACREL was intended to be DEC's offered solution to the want of a macro assembler for the PDP-8 in the disk-based operating system era.
Unfortunately, it never achieved widespread use outside of DEC.
|Internet, same links as above
SMAL is a series of cross-assemblers initially created by Douglas W. Jones. He wrote the initial versions in Pascal but later ported it to C. Some versions of SMAL — such as the SMAL32 version linked above for its wonderful manual — are machine-independent, meaning that it provides only the skeleton of the assembler, which is not able to generate code for any particular machine. Other versions of SMAL were targeted at specific machines, mostly 8-bit microcontrollers. Oddly enough, Dr. Jones did not base his
pal.c PDP-8 cross-assembler upon SMAL. (See palbart below for more on that thread of history.)
Some of the differences listed below mean that although the basic syntax of SMAL8 is solidly in the PAL-III family, SMAL8 is likely to assemble only relatively simple PAL programs as-is. The most critical differences are the loss of inline literals and the difference in conditional assembly. New code would simply be written to avoid these problems.
If you read through the SMAL32 manual and see differences relative to PAL syntax but don't see the difference documented below, chances are that Vincent Slyngstad fixed these differences in SMAL8. For example, like PAL8 but unlike SMAL32, SMAL8 uses
/ to introduce comments, defaults to octal, allows
* to set the output origin, and uses the
EJECT pseudo-op rather than
PAGE to put a page break into the output listing.
SMAL8 has many feature additions relative to PAL8:
- relocatable output
ENDMAC: MACREL-like macro feature
GLOBAL: module and linkage support
>comparison operators in expressions
>>>bit shifting operators in expressions
- double and single quoted strings; PAL8 supports only double-quoted single-character constants
- labels separated from the code by either comma (PAL8 style) or colon (SMAL32 style)
- arbitrary radices in numeric constants using
r#nsyntax, which gives
- the ¦ operator is allowed as an alias for PAL8's
!form of Boolean OR
- end assembly with either
$(PAL8 style) or
SUBTITLEpseudo-ops for setting listing page titles
TEXTbut stores real unpacked ASCII
- many more pseudo-instructions defined: DF32, DECtape, etc.
Some things are simply different in SMAL8 as compared to PAL8:
- powerful expressions in SMAL allow modern
ENDIFfor conditional assembly
PAGEtakes no argument, as in SABR
There are a few features removed relative to PAL8:
- multiplication is not allowed in expressions;
*was given the PAL8 meaning, and
^is not implemented
- division is not allowed in expressions;
/was given the PAL8 meaning, and
%is not implemented
- neither the
[N]syntaxes for inline literals work; parens used for groups and lists instead
- some IOT instructions PAL8 knows do not have predefined symbols:
The data storage specifier feature of SMAL32 was removed in SMAL8, since it doesn't make much sense in the 12-bit world of the PDP-8. (That is, the byte (
B), halfword (
H), threeword (
T), and fullword (
W) pseudo-ops.) Use
|Internet, PiDP-8/I project
palbart is a popular fork of the
pal.c assembler by Douglas W. Jones and Rich Coon, originally spun off by Gary A. Messenbrink — and later enhanced by several others — to support the fleet of PDP-8/e computers in the Bay Area Rapid Transit system; thus the name.
The PiDP-8/I software distribution includes a version calling itself "pal-2.13, 03 May 2015."
If you place a
*.pal file in either the
examples subdirectories of the software distribution, then type
make, the build system will find your file and generate several output files named after it:
obj/*.lst— the assembler's text listing output, giving the assembled machine code alongside the source code, plus any error messages
bin/*.pt— the machine code output in RIM paper tape format, suitable for loading into SIMH's PDP-8 simulator
boot/*.script— a SIMH init script that deposits the machine code into the PDP-8 simulator's core memory and starts it running; pass the file name to
This makes for a very smooth code-build-run-debug cycle:
- Debug; if still buggy, goto step 1.
There are many different versions of
palbart floating around on the Internet, and earlier versions have bugs or features that prevent it from being completely compatible with the PAL family assemblers above. The most likely to affect existing programs is that some versions of
palbart do not chop symbols off at 6 characters. Some code depends on this happening; for example, the assembled code may refer to a label with 7+ characters in one location and with 6 in another location, and expect the assembler to refer to the same location in both places. The version of
palbart that we ship with the PiDP-8/I software distribution does not have this incompatibility. If you know of an incompatibility relative to PAL8 in particular, please file a bug report ticket.
|see its home page
This is a PDP-8 assembler accepting the PAL-III syntax for Unix type systems.
I am listing it here along with
palbart because there are known weaknesses in
palbart. If you know of more, please file them.
palbart currently has no central development home, so it is possible that the PiDP-8/I project will end up hosting an improved version.
Meanwhile, it seems like a good idea to me to have a second option at hand when cross-compiling code on a POSIX type platform for a PDP-8.
Copyright © 2017-2018 by Warren Young. This document is licensed under the terms of the SIMH license.