In the previous page I said that all symbolic information for a PDP-11 is kept in one “machine description file’. Well, this sound like a good idea at first.

But if you generate your 2nd machine description file, you will notice what an problematic concept this is: You will find your self copy&pasting tons of register definitions, which differ only slightly in their start addresses, if at all.

And the file is quite filled up with text: The question: "what modules are in my machine, and at which addresses are they sitting?” should be answered by one quick look into the machine description file.

Separate module “definition” from module “usage”.

Here the concept of the “machine module library” comes in.

The idea is to separate the definitions of “modules” (plug-in cards, or description of standard register address blocks) from their usage in specific machines.

A module is the set of register and bit definitions in a device definition: allmost all text without the "[devicename]" and “Info=” section.

These module defintions are kept in a separate file, and are included by device definition.

Example

You have this module definition in “machines\pdp11_serial.modules”:

define(Module_SLU,`
Info="Standard serial console terminal"
RCSR= _offset($1,0) ;"Receiver Control/Status Register";Bits.SLU.RCSR
RBUF= _offset($1,2) ;"Receiver Data Buffer";Bits.SLU.RBUF
XCSR= _offset($1,4) ;"Transmitter Control/Status Register";Bits.SLU.TerminalXCSR
XBUF= _offset($1,6) ;"Transmitter Buffer Register";Bits.SLU.XBUF       ')

And your “pdp11.ini” may look like this to define two serial interfaces:

include (`pdp11_serial.modules')

[Console Terminal]
Module_SLU(177560)
Info="Serial console terminal and aux registers on CIM card"

[Console TU58]
Module_SLU(176500)
Info="Serial TU58 interface on CIM card"

And this is the final definition file after macro expansion (it’s name is always “tmp_pdp11gui_m4_out.ini” in your “%TEMP% directory).

[Console Terminal]
RCSR= 177560 ;"Receiver Control/Status Register";Bits.SLU.RCSR
RBUF= 177562 ;"Receiver Data Buffer";Bits.SLU.RBUF
XCSR= 177564 ;"Transmitter Control/Status Register";Bits.SLU.TerminalXCSR
XBUF= 177566 ;"Transmitter Buffer Register";Bits.SLU.XBUF
Info="Serial console terminal and aux registers on SLU card"

[Console TU58]
RCSR= 176500 ;"Receiver Control/Status Register";Bits.SLU.RCSR
RBUF= 176502 ;"Receiver Data Buffer";Bits.SLU.RBUF
XCSR= 176504 ;"Transmitter Control/Status Register";Bits.SLU.XCSR
XBUF= 176506 ;"Transmitter Buffer Register";Bits.SLU.XBUF       
Info="Serial TU58 interface on CIM card"

You see:

  • a Macro “Module_SLU” is defined.
  • It has one parameter "$1", which is an octal base address.
  • You call this macro by just typing “Module_SLU(177560)”
  • The module definition has a generic “Info=” line, which is overwritten.

Text macro substitution with “M4”

The module inclusion is implemented as a macro substitution process. It works like the C-Makro preprocessor “cpp”, (and has nothing todo with the PDP-11 MACRO-11 assembler !) But instead of “cpp”, I use the bigger and less known “M4” macro preprocessor.

I choosed M4, because it is rather powerful, and because it is quite "retro": this Unix program was developed by Kernighan & Ritchie in 1977 ...

M4 is called by the little cmd file “m4.bat”. You can edit this file to use another macro preprocessor, or to change the include path for module libery files.

Debugging macro expansion

M4 does never abort on error. In case of syntactic errors, it simply eats up ill-defined or ill -used macro definitions. To debug the macro expansion, you have just two instruments:

  1. Edit M4.BAT and insert an “PAUSE” command at the end. Then the execution stops after the M4 run and you can check out M4’s error messages, which are pretty clear.
  2. Examine the result file “%TEMP%\tmp_pdp11gui_m4_out.ini”