CTSS: Fortran II translator

Fortran became a very popular language for scientific computation on the IBM 7x series soon after its creation in 1957. Although it could run as a FMS batch job, it was not available for online users of CTSS - according to Tom Van Vleck 'IBM FORTRAN II would not run in CTSS foreground, because the FORTRAN compiler was a complex multi-pass monster.'

What was available was a translator from Fortran to MAD called MADTRN. This would take a Fortran file as input (with name2 of MADTRN), translate it to MAD and then compile it. The CTSS Programmer's Guide does provide some warnings on its use, however:

MADTRN does not always produce perfect results and, therefore, should not be used unless absolutely necessary. MADTRN assumes a working Fortran program and therefore MADTRN diagnostics are minimal.

In any case, let's try this out on CTSS by implementing the TPK algorithm.

/images/ctss/fortran-punched-card.png

Blank Fortran punched card. Source: IBM 7090/7094 Programming Systems: FORTRAN II Programming

TPK in Fortran II

This is based on Knuth's Fortran I version in the original paper. See the file on Github or the annotated version below.

The source format, as shown in the illustration above, is fixed, with C in column 1 indicating a comment, line numbers in cols 1-85 and code starting at column 7.

  C     TPK ALGORITH IN FORTRAN II
        FTPKF(X)=SQRTF(ABSF(X))+5.0*X**3                         
  C     MAIN PROGRAM
        DIMENSION A(11)
        N=11
        PRINT 100
   100  FORMAT(23HPLEASE ENTER 11 NUMBERS)                       
        READ 101,A
   101  FORMAT(F9.4)
        PRINT 102
   102  FORMAT(11HRESULTS ARE)
        DO 3 J=1,N                                               
        RESULT=FTPKF(A(J))
        IF (RESULT-400.0) 2,2,1                                  
   1    PRINT 103
   103  FORMAT(9HTOO LARGE)
        GO TO 3
   2    PRINT 101,RESULT
   3    CONTINUE
        STOP
        END

The function to be called is on line ②, and is an example of a single expression function. Note that functions have to end with the letter F, including built in ones like SQRTF.

Variable types are indicated by the first letter: I - N means an integer, otherwise it is floating point.

Strings can be printed, as shown on line ⑦, but need to be incorporated in the format definition as the string length followed by H.

Arrays can be read in by a single statement, but are stored in reversed order on the IBM 7x series, so the first line of input goes to A(11).

Line ⑫ introduces a loop. ⑭ is a 'computed if', with the test expression being compared against zero and a branch taken to the first, second or third label if the result is less than, equal to or greater to the test. So here if RESULT is > 400 control will transfer to label 1, otherwise to label 2. This is the only 'if' syntax available in Fortran II.

Compiling the program

To compile, run MADTRN TPK, optionally with the (LIST) switch.

Noe that MADTRN will create TPK MAD as its output before compiling it, so if you already have TPK MAD from the previous post in your directory it will be overwritten.

As indicated by the warning in the manual, if there is a mistake it is unlikely to be caught until the MAD program is compiled which means you need to trace back from the translated source. The only MADTRN diagnostic I could get was if I forgot the END statement:

****ERROR 20
*****NO END CARD *****
PROBABLE ERROR IN MADTRN FILE.
MAD FILE CREATED,USE AT OWN RISK.

Otherwise, the compile and execution is straightforwards:

madtrn tpk (list)
W 1905.1
LENGTH 00205.  TV SIZE 00006.  ENTRY 00055
R .033+.066                               
           
loadgo tpk
W 1905.2
EXECUTION.
PLEASE ENTER 11 NUMBERS
...

The MAD output of the translator is reasonably clean so could be used as a starting point for further development.

Further information

The IBM manual IBM 7090/7094 Programming Systems: FORTRAN II Programming is a short and readable guide to the language.

There's lots of information about early Fortran at softwarepreservation.org.

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: 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


Next →