CTSS: MAD language

MAD - the Michigan Algorithm Decoder - was a ALGOL inspired language commonly used for scientific programming on the IBM 7x series of computers. It was conceived by Bernard Galler and colleagues at the University of Michigan in 1959. A version from around 1963 was ported to CTSS, where it was used to write many of the system utilities such as LISTF.

To demonstrate MAD and how to write programs in it on CTSS, I will show an implementation of the TPK algorithm.

What is the TPK algorithm?

See the repo project-tpk for more details, but basically this was developed by Donald Knuth and Luis Trabb Pardo for a paper about early (pre-1957) languages. It does the following

    read 11 numbers to an array
    for each x in in reverse order of the array
        calculate √|x| + 5x³
        print that number if ≤ 400, else print TOO BIG

which is not supposed to be a useful task, but demonstrates many typical language features like I/O, loops, arrays, functions and conditionals.

TPK in MAD

Here is the complete program.

          R TPK ALGORITHM IN MAD                                 ①
          R FUNCTION F                                           
           INTERNAL FUNCTION(X)                                  ③
           ENTRY TO F.                                           
           FUNCTION RETURN SQRT.(.ABS.X) + 5 * X.P.3             
           END OF FUNCTION                                       ⑥
          R MAIN PROGRAM                                         
           INTEGER N,J                                           ⑧
           N = 11                                                
           DIMENSION NUM(11)                                     ⑩
           VECTOR VALUES FMT = $F9.4 *$                          ⑪
           PRINT COMMENT $PLEASE ENTER 11 NUMBERS$               ⑫
           THROUGH INPUT,FOR J=0,1,J.GE.N                        ⑬ 
INPUT      READ FORMAT FMT,NUM(J)                                ⑭
           PRINT COMMENT $RESULTS ARE$                           
           THROUGH CALC,FOR J=N-1,-1,J.L.0                       ⑯
           RESULT = F.(NUM(J))                                   
           WHENEVER RESULT.G.400                                 ⑱
           PRINT COMMENT $TOO LARGE$                             
           OTHERWISE                                             
           PRINT FORMAT FMT,RESULT                                     
CALC       END OF CONDITIONAL                                    ㉒
           END OF PROGRAM

Numbers in circles (like ①) are for reference below, not part of the program. You can download the machine readable file from github.

The layout is fixed, with

  • columns 1-10 containing an optional line label
  • column 11 contains R if the line should be treated as a comment (such as line ①), or a digit if it is a continuation line, blank otherwise
  • code is in columns 12-72
  • columns 73-80 are optional sequence numbers, useful for punched cards

Lines ③-⑥ contain the function F. to do the calculation. Functions can share code have multiple entry points indicated by ENTRY TO. Functions are denoted by a dot on the end, eg F., SQRT., whereas language operators have dots before and after, like .ABS. and .P. (power).

The main program starts at ⑧ with some variable definitions. Default type for undefined variables is floating point (can be overridden per program file with eg NORMAL MODE IS INTEGER). ⑩ introduces an array of floats called NUM.

⑪ defines and initialises an array of six-bit BCD characters; the $ indicates the character type. The contents of ⑪ is a format specification, similar to a C scanf string, requesting floating point.

⑬-⑭ is a loop, delimited by the label INPUT, to read in 11 floating point numbers from the user.

⑯-㉒ is another loop to execute the function on each array item in reverse order, with a conditional in ⑱-㉒ to display TOO LARGE or the result of the function.

One other language feature not used here is the ability to abbreviate keywords: instead of typing WHENEVER you can use W'R, or E'M instead of END OF PROGRAM.

Compiling and running

See the guides on how to upload or edit files to enter the program into the system.

MAD TPK will compile this file and create an object file TPK BSS. The compiler has two optional arguments

  • (LIST) to produce a full listing file in TPK BCD
  • (SYMB) to include symbols in the object file for debugging.
mad tpk (list)
W 1831.4
LENGTH 00211.  TV SIZE 00007.  ENTRY 00040
R .016+.016

Run the program directly with LOADGO TPK, or save it to an executable file that can be used later, and run it via

    LOAD TPK
    SAVE TPK
    R TPK

(see this previous post on how loading works on CTSS.)

When running the program, you need to include a decimal point in each item to indicate its type, so you'd enter 1 as 1.. An example run:

loadgo tpk
W 1831.7
EXECUTION.
PLEASE ENTER 11 NUMBERS
10.                    
-1.
1.
2.
3.
4.
4.3
4.305
4.303
4.302
4.301
RESULTS ARE
 399.8863  
TOO LARGE
TOO LARGE
TOO LARGE
 399.6086
 322.0000
 136.7320
  41.4142
   6.0000
  -4.0000
TOO LARGE
  EXIT CALLED. PM MAY BE TAKEN.
R .150+.016

See github for the compile/run transcript, and the full listing.

Further reading

I have not been able to find the language reference for this particular version of MAD, but this manual from the University of Illinois on bitsavers is close. Also there is Bernard Galler's introduction to programming using MAD, The Language of Computers.

CTSS project director Fernando Corbato wrote an abbreviated guide to MAD in MIT Computer Center Memo 213, but the print quality is not great so this is hard to read.

ELIZA is a good example of a larger program written in a mix of MAD and assembly language.

I have written about GOM (Good Old MAD), a later version of MAD for MTS on the System/370 over at try-mts.com.

Questions, corrections, comments

I welcome any questions or comments, and also especially any corrections if I have got something wrong. Please email me at rupert@timereshared.com


CTSS: Programming

Today we'll look at languages and other programming facilities on CTSS. Page numbers listed below are from the CTSS Programmer's Guide,

As in the previous section on CTSS commands, in some cases a command is described in the guide but is not available on the emulated systems, which is shown using strike through. This is because the CTSS we have today was reconstructed from a listing tape which does not include every command that was present then.

Languages

Command Meaning Guide
FAP IBM 7094 Assembler p306
MAD Michigan Algorithm Decoder p315
MADTRN Fortran II to MAD translator p318
LISP List Processing Language p314
AED ALGOL Extended for Design p293
BEFAP Bell Laboratories' 7094 Assembler p294
COGO-90 Coordinate Geometry Language p295
COMIT String Processing Language p296
DYNAMO Model Simulation Language p303
GPSS General Purpose System Simulator p313
SNOBOL String Manipulation Language p319
OPS Online Programming System p320
TIP Technical Information Program p321
FOR4 Fortran IV to MAD Translator p322
FORMAC Desk Calculator p324

The languages CTSS was developed in (FAP assembly and MAD) are available, along with a translator from FORTRAN to MAD and an early LISP implementation.

The other languages are not available. I speculate that these were not maintained by the Computation Center hence were not on the listing tape used to reconstruct CTSS. The IEEE 50th anniversary retrospective document has a section on the origin and importance of some of these languages.

Loading, saving and starting programs

Command Meaning Guide
LOAD Load a program into memory p422
L Load a program into memory, providing more table space p422
LOADGO Load a program into memory and start it p422
VLOAD Load a program into memory, remove the loader p422
NCLOAD Load a program into memory, remove the loader and commons p422
LDABS Load a program into memory without relocation, p428
USE Supply missing modules when loading a program p422
SAVE Save a dormant program p341
MYSAVE Save a dormant program and the state of its files p341
START Start a program in memory p430
RSTART Restart a chain of programs in memory p430
RESTOR Loads a program into memory from disk p430
RECALL As RESTOR, but also restores old command line args p430
RESUME Loads and runs a program. Can be abbreviated to R p430
CONTIN Load and continue a saved chain of programs p430
DO Execute a saved program from common files p440
LAED Loader for the AED language p432
PLOAD Simulate the loading process p441
BLIP Show a message every few seconds of program execution p442
RUN Used by TIP to execute programs p443

The paradigm for creating user programs and running them is different from modern operating systems. As an example, on Unix if you have a main program main.c and two modules a.c and b.c you might compile them to a binary foo as follows:

    cc -c a.c
    cc -c b.c
    cc -o foo main.c a.o b.o

The first two commands make object files a.o and b.o. The last command compiles main.c and then invokes the linker to bind together the three modules into an executable file called foo.

Now let's say we are on CTSS and programming in MAD instead of C, so now we have three files A MAD, B MAD, and MAIN MAD. First we compile each of the components:

    MAD A
    MAD B
    MAD MAIN

Now we have object files called A BSS, B BSS, MAIN BSS.

Instead of linking them to a disk file, we load them into memory:

    LOAD MAIN A B

At this point you can start the program immediately - without ever creating an executable file - with

    START

The LOADGO command is basically a LOAD followed by a START.

Instead of starting, we could save the memory image to a SAVED file:

    LOAD MAIN A B
    SAVE FOO

This creates a file called FOO SAVED. It can then be loaded and started with RESUME, or simply with R:

    R FOO

SAVE can be run at any time for a user program. Say you have a program that on start up reads a configuration file, parses it and then enters a loop where it prompts for a command and prints a response. (For example, ELIZA!) If you pressed the interrupt key after the config file was loaded and then ran SAVE, the file it creates would allow you to restart the program at the same point, ie within the prompt-response loop rather than right at the beginning. Similarly, if you have a job which does a lot of calculation, you could interrupt it, save the current state, log off, and come back later and restart it at the saved point.

These are the load/save commands you will use the most often; the others in the table are useful in specific scenarios. For example, L allows more object files to be loaded at the expense of space available for the program.

Library management

Command Meaning Guide
EXTBSS Extract a BSS file from a COMBIN-ed library p411
UPDBSS Update a BSS file in a COMBIN-ed library p411

Libraries of object (BSS) files are created on CTSS by using COMBIN. For example, to create library MYLIB BSS from two objects A BSS and B BSS:

    COMBIN * MYLIB BSS A B

(the * means don't change the line numbers in the object file).

Once created, these libraries can be manipulated with the above commands.

Using our example from the previous section, instead of loading each object file:

    LOAD MAIN A B

with a library file we can now use the (LIBE) option:

    LOAD MAIN (LIBE) MYLIB

Debugging

Command Meaning Guide
FAPDBG Symbolic debugger for assembly language programs p449
MADBUG Symbolic debugger for MAD language programs p459
DEBUG CTSS symbolic debugger p486
PM Print post mortem information about a program p473
STOPAT Set a breakpoint p479
PATCH Modify a program's memory image p479
TRA Transfer when reaching a certain address p479
SPATCH Absolute program patching p477
STRACE Trace a running program p480
SD Supervisor debug printing p478
SP Supervisor debug patching p478
STOMAP Print storage (memory) map p503

The standard library

CTSS also had a comprehensive library of functions available to programmers, both from assembly and high level languages like MAD. These are documented in the CTSS Programmer's Guide section AG (p108 onwards) and cover

  • Console I/O
  • File I/O and status
  • Tapes and pseudo tapes
  • Error handling and program status
  • Command and subsystem control
  • Conversion (eg number to BCD string)
  • Timers

"Pseudo tapes" here means when a program tries to access a tape - eg via language constructs like MAD's READ BCD TAPE statement - it is redirected to a disk file, as regular users would not have access to physical tapes.

Questions, corrections, comments

I welcome any questions or comments, and also especially any corrections if I have got something wrong. Please email me at rupert@timereshared.com


CTSS: RUNCOM and FIB: scripting and background jobs

Another first for CTSS was the idea of collecting a sequence of interactive commands into a script file that could be run as a single unit, which helped simplify complex or repetitive tasks. The command that does this is called RUNCOM, for Run Commands. This influenced the Multics shell and the terminology carried over to Unix in file names containing the letters rc, eg /etc/init.rc.

Associated with this is FIB, the Foreground in Background batch job scheduler, which allows you to execute RUNCOM jobs without being logged in. Let's take a look at both.

/images/ctss/running-fib.png FIB running a job submitted by GUEST.

Using RUNCOM

At its simplest, this is just a text file with name2 of RUNCOM containing a list of commands to run in order. For example, if I am editing, printing, compiling and running a program FOO I could write the following to a file DEV RUNCOM

EDL FOO MAD
P FOO MAD
MAD FOO
LOADGO FOO

and then type RUNCOM DEV to execute it.

By using parameters we can generalise this to work with other source code files. Parameters are introduced with the CHAIN statement.

CHAIN PROG
EDL PROG MAD
P PROF MAD
MAD PROG
LOADGO PROG

and then executed by typing, for example RUNCOM DEV FOO.

We can generalise further to allow MAD and FAP code to be developed by noticing that the name2 and translator can be parameterised as one item:

CHAIN PROG TRANS
EDL PROG TRANS
P PROF TRANS
TRANS PROG
LOADGO PROG

and run as RUNCOM FOO MAD

Optional parameters can be introduced using (NIL). Say sometimes I want to give options to the translator command, like (LIST). I can change the runcom file to be:

CHAIN PROG TRANS OPT
EDL PROG TRANS
P PROF TRANS
TRANS PROG OPT
LOADGO PROG

and then invoke as RUNCOM FOO MAD (NIL) if I don't want any options, or RUNCOM FOO MAD (LIST) if I want the compile command to be MAD FOO (LIST).

(END) is a similar parameter which will end the line at that point if detected.

Finally, a line starting with * in the runcom file will act as a comment; a line starting with $ will be echoed to the console.

Using FIB

FIB allows you to submit a runcom file for later execution. It is invoked as:

    FIB NAME1 -LIMIT- -TIME- -DAY-

where NAME1 is the name1 of a runcom file, eg FOO for FOO RUNCOM.

The next three parameters are optional. LIMIT sets a maximum CPU time in minutes that the job can run for, with a default of 5. The last two set a time and date before which the job cannot start.

Once you submit a job, you can cancel it with DELFIB or query it with PRFIB. Only one job can be submitted at a time.

fib make
W 914.1
R .016+.016
           
prfib
W 914.3
       
JOBNAM  LIMIT   DATE  TIME
                          
  MAKE     5   03/09 0914.1
                           
R .016+.016

In addition to any time/date argument, the job will not run until you have logged out. Behind the scenes, the FIB job switches to your ID and executes the job, as can be seen from the screenshot of the console at the top of this post.

This is because CTSS only allows one task per ID to be running at a time. Had you tried to log in while the job was running, you would see a warning and if you continued the FIB job would be cancelled.

After the job has finished, you will see its console output in a file called $$$FIB OUTPUT.

Further details

See the CTSS Programmer's Guide p326 for RUNCOM and p287 for FIB.

Questions, corrections, comments

I welcome any questions or comments, and also especially any corrections if I have got something wrong. Please email me at rupert@timereshared.com


CTSS: ED and friends: online editors

Colossal Typewriter on the PDP-1 was earlier, but the CTSS text editors were probably the first used for actual work. In this article we'll look at how to do simple editing tasks using EDC and EDL on CTSS.

/images/ctss/ed-session.png A sample session using EDL, changing two lines in a file.

Historical editors on CTSS

The first disk-based text editor on CTSS was invoked by either of the commands INPUT and EDIT, the first creating a new file for insertion and editing, and the second for editing an existing one. These worked only on card image files and would automatically number the sequence iDs for you. Actions were limited to entering text and either replacing or deleting the contents of a card/line by referring to its sequence number.

A more advanced, context aware editor called ED was introduced later, based on concepts and commands introduced in the TYPSET text processing system (which we will look at it a later post).

None of these editors are available on the CTSS we have today, However, we do have two editors which were developed after ED with a similar interface, EDC for card image files and EDL for line marked files.

Invoking

There are different commands for card image (EDC) and line marked (EDL) files and you need to select the correct one based on the file you are editing. See Files and Directories for a discussion of the two formats; if you are looking at an existing file and are not sure of the format, try running P on it: if it shows sequence numbers, use EDC.

Invoke the editor by giving the name of the file you want to work on, eg EDL HELLO MAD. If the file does not exist, it will create it.

If you have interrupted a previous editing session you may see a message like Old file (INPUT 5 --Do you wish to delete it?; it's safe to reply yes.

Input and Edit mode

The editors have two modes, input where you can type lines and edit where you can give commands. New files being edited will start up in input mode, existing files in edit mode. Press Enter at the start of a new line to switch between the two.

Edit mode commands have a long form and an abbreviation which we will show in brackets in the discussion below.

Getting in and out

In edit mode, typing file (fl) will save the file and exit the editor. Giving a parameter will save it under a new name.

The quit (q) command will exit without saving.

Example: creating a new file

Here's what this looks like when I edit a new file, add text and then save and exit:

edl try mad
W 1847.7
 FILE    TRY   MAD NOT FOUND.
Input:                       
	PRINT COMMENT $HELLO FROM ED$
	END OF PROGRAM

Edit:
file 
*
R .016+.016

Note the blanks at the start of the PRINT and END program lines; these were introduced by pressing Tab. ED knows the correct indentation for the languages used on CTSS.

The blank line after END OF PROGRAM tells ED to go to Edit mode, after which I give the file command to return to the command level.

Moving around

The editor maintains an internal pointer on which line it is on in the file.

The command top (t) and bottom (b) move to the start and end of the file. next (n) will move one line down, or you can give it a numeric parameter to move down a certain number of lines.

locate (l) takes a string as a parameter and finds the first line starting at the pointer where the string matches. It will print the line if found and move the pointer, otherwise it will print an error message.

Printing text

Type print (p) to show the current line you are on. You can give this a numeric argument to print more than one line.

A simple way to print the whole file is to move to the top with t and then typing something like p 1000.

Changing text

Pressing Enter while in edit mode will switch you to input mode. Type lines of text, which will be inserted after the current line pointer, and then type Enter at the start of a new line to return to edit mode.

While in edit mode, use the command insert (i) followed by a line of text (ie without pressing enter before the text) to insert a single line and remain in edit mode.

retype (r) followed by a line of text will replace all of the current line. delete (d) will delete it.

change (c) will replace parts of the line by matching text. An example that will replace the word "from" with "to" on the current line.

c /from/to/

The / are delimiters and can be replaced with any character that is not in the search or replace text.

change takes two parameters: number of lines and g. The first specifies how many lines to search forwards and do replacements. The second is a flag meaning global, if set it will replace all instances of the from text on each line.

So to replace every instance of "before" to "after" in the whole file you could do:

c QbeforeQafterQ 1000 g

EDC and sequence numbers

EDC has special handling for card sequence numbers, which normally occur in columns 76-80.

The ncols (nc) command determine how many columns are available for non sequence number text, and is normally set to 72.

serial (sr) normally takes two parameters, m and n, indicating the start sequence number and the increment. Normally these are both set to 10, so you will get sequence numbers 00010, 00020 etc. serial off will turn off sequence number generation; this can be restored with serial on.

Note the EDC will automatically resequence the numbers in an existing file unless you specify serial off before you start.

Command summary

Command Short Meaning
bottom b Move to bottom of file
change c Change a line based on text
delete d Delete the current line
file f Save and exit
insert i Insert a line
locate l Find a line based on text
ncols nc (EDC) Set columns to use for text
next n Move down one or more lines
print p Print lines
quit q Exit without saving
retype r Replace a line
serial sr (EDC) Set sequence numbering
tabset ts (EDC) Set tab stops
top t Move to top of file

Further details

See the CTSS Programmer's Guide p333 for the common set of ED commands and then p351 and p372 for adjustments made to EDL and EDC respectively.

Questions, corrections, comments

I welcome any questions or comments, and also especially any corrections if I have got something wrong. Please email me at rupert@timereshared.com


CTSS: Getting data in and out

There are two approaches to getting data in and out of CTSS - one involves using the contemporary tools of the operating system, the other is to use facilities provided by the s709 emulator. We'll look at both, but first we need to understand what I/O meant when CTSS was originally running.

/images/ctss/ibm-029-card-punch-montage.jpg Using the IBM 029 Card Punch. Source: deepblue. Copyright: Board of Regents, University of Michigan.

Data interchange in the 1960s

At the time there were basically three media that could be used.

Printed paper - as typewriters were used as consoles, a printed record of what you were doing would be created automatically. But the print quality was not great, and it would also be slow to print a large file. So computer facilities like MIT offered ways to print on a faster and better quality printer.

Punched cards can be used for both input and output of programs and data. A user could punch a set of cards offline on a dedicated key punch (see image above), and get them loaded into the system. They could also get the computer to punch out cards and use the resulting deck as a backup or a way to transfer the data to another computer. At roughly a line of 80 characters per card, this only made sense with relatively small amounts of data; they were also slow to read.

Magnetic tapes was the choice for large amounts of data needed to be backed up or transferred elsewhere, but these were more expensive. Although operators and system programmers would use tape regularly, I believe end users would be less likely to use tape, at least at the time of CTSS.

(One further option was paper tape, but I believe this was used on smaller computers like the PDP-1.)

Mapping this to emulated systems

Card punches and magnetic tape drives are things you are very unlikely to have access to today - even printers are getting more scarce - so how does this work with an emulated system?

Put simply, it maps to files on your host system. Printer output goes to a single text file. Cards and tape map to binary files whose format is determined by the emulator, which provides tools to convert them to PC readable data at the cost of losing the original format.

Let's look at some ways we can use to do data interchange, starting with facilities provided by CTSS.

Printing and punching files via RQUEST

On the real 7094, printing and card punching was not done online due to the CPU load it would place on the system. Instead, users could request files to be printed and punched. Several times a day, the CTSS operators would collect the files on to a tape and bring this to a smaller system for printing and punching, and then distribute the results to users. The command to initiate this on CTSS was RQUEST.

We can use this facility with the emulator as well.

  1. While online, type RQUEST PRINT name1 name2 to request printing of file name1 name2 or RQUEST DPUNCH name1 name2 to request punching. Wildcards are OK, so you could type RQUEST PRINT * BCD to produce a print out of all compile listings.
  2. Shut down CTSS
  3. Run dskedtctss on your host
  4. You will need to press Enter a few times and then `q` when done.

If you are running the ELIZA version of ctss-kit, all printer output will be in output/sysprint.txt and each punched file will be a separate file based on the original filename in output.

For the upstream version of ctss-kit, you will need to convert the output tapes produced by dskedtctss as follows:

  • Printouts: Run bcd2txt -p sysprint.bcd sysprint.txt.
  • Punches: Run punchctss syspunchid.bcd syspunch.bcd .

Downloading files via the emulator

We can use a utility provided by s709 called extractctss to get files from inside CTSS to your host machine. Usage is:

extractctss file-type name1 name2 prob prog local-file

file-type should be t for card image files and l for listings.

Note that the CTSS system should be shut down when you do this.

A sample run to get the HELLO MAD source file from the guest user:

extractctss t hello mad m1416 guest hello.mad

This will produce hello.mad in your current directory.

extractctss can also download several files in batch mode; see the ctss-kit README for more details

Should you use RQUEST or extractctss? I use both and think RQUEST is useful when you are logged into CTSS, looking at files and picking several to print or punch. extractctss is great for automated downloading.

Uploading files via the emulator

You can also go the other way, uploading files from your host machine to CTSS. This is a two step process.

First, convert the file into a tape format readable by the upload program using obj2img. Here's an example to prepare upload.mad to become file UPLOAD MAD on the guest account:

obj2img -a " M1416GUEST " -f upload -e mad -t -o upload.img upload.mad

The -a flag determines the account to send it to; the problem number (M1416) must be right justified into 6 characters, and the programmer number (GUEST) must be left justified. Both must be in capital letters.

The -f and -e flags determine the name1 and name2 of the file on CTSS.

-t specifies card image format; obj2img can also do line marked, binary files and other special formats. See obj2img -h for options.

Second, to get this image file loaded into CTSS, run setupctss as follows:

setupctss upload.img 

IBM 7094-CTSS Simulator 2.4.3


 ATTACHING TO  M1416 GUEST                                              
 COPY TO TEXT FILE UPLOAD    MAD                                        
 DISK INITIALIZATION COMPLETE.                                          
 CTSS IS FINISHED. YOU MAY NOW CLEAR CORE.

You can then remove the .img file.

Areas to explore

The Disk Editor on the real CTSS system also allowed you to upload files by giving the operators a card deck, but I don't believe this is supported on the s709 virtual system.

CTSS provided a number of tape handling commands so you could MOUNT a tape and then associate files on there with entries in a UFD to it can read/written. These commands are available, but are not fully supported by s709 I believe.

Questions, corrections, comments

I welcome any questions or comments, and also especially any corrections if I have got something wrong. Please email me at rupert@timereshared.com


Next →