1970
The IBM System/3 has a special place in my heart.
It
was the first computer I ever saw up close. It was at Evanston Township High
School, Evanston, Illinois, in 1970, replacing the old "unit
record" machines that had occupied that same room just a few months
earlier. It was a bare-bones model 10, 8k RAM, no disk drives, slowest
printer (100 lpm, I believe) and MFCU (120cpm
read, 60 punch & print), and a 5475 data entry
keyboard so the computer could be used as a data entry unit (IBM called
them “Data Recorders”); they were new for the 96-column card and held a
card’s worth of data that could be edited before the card was punched.
IBM
also introduced a new card machine for the new, smaller card, called the MFCU
(Multi-Function Card Unit). Machines for the 80-column card were dedicated
to specific functions: reading, punching, interpreting, and sorting, but the
MFCU was able to do it all. I have a lot of respect for the MFCU. It’s
technology that Honeywell tried to duplicate but did a poor job of. IBM’s
always worked a lot better. For its day, it was really a cool machine, and
was very reliable. I still recall a lot about the System/3.
I
used to carry the hex nut driver in my wallet, the same size that the CE from
IBM would use to defeat the don’t-run-when-the-cover-is-up switch inside
of the MFCU. Now I could watch the MFCU run with the cover up. It was very
impressive with its aircraft landing light over the read station. I was
impressed with the fact that this machine was the first to use optical card
reading instead of the wire brushes.
I had selected Computer Programming for my sophomore year in high school out of
lack of finding anything that sounded more interesting, and wasn't that
enthusiastic about the class. Things were off to an acceptable start, and I was
learning to code in RPGII. I had no idea how computers worked and still
thought that there was some magic involved. Then one day, I had an enormous
AHA! experience. I realized that computers don't do anything magical at
all. They only perform one operation at a time, in sequence, one step after
another. Only they do these operations really fast! Now it all made sense!
I quickly excelled in my studies, raced through all the assignments, and
began writing things that were more interesting. Still coding in RPGII, I wrote
a clever little program that performed powers of two, starting
at one and adding the value to itself until it filled the entire page, which
was challenging since the largest numeric value supported is only 15
digits. Then I wrote another program that printed out trigonometric values for
0 through 90 degrees, and then another one that printed out block letters. My
computer programming teacher, Mr. Arndt, was certainly one of the best teachers
I've ever had. He led me to believe that he knew far more than he did, and
he encouraged me to go as far as I wanted, without any ego about having
a student knowing more than the teacher.
One day, he showed me a one-card program that turned the column indicators on
the 5475 keyboard into a digital clock, counting from 00 to 59, over and
over, at 1-second intervals. He showed me the program, and before I could see
what it was doing, he had the card back in his pocket. When I asked him
for a copy of it, he said no. Instead, he handed me a copy of the
"Components Reference Manual" and encouraged me to figure out
how to write my own.
I'd been made a lab aid by that time, which meant that I could be in the
computer room without a teacher present, but if another student
had questions related to their assignment in the computer programming
class, they took priority over what I was doing. Otherwise, the computer
was at my disposal! I was in heaven, and I spent endless hours working on pet
project after pet project.
With only 8k RAM, RPG II became too limiting, and with no disk drive, there was
no assembler available, so once I had the instruction set manual, I began
teaching myself machine language. I found the instruction set a gold mine of
programming adventures that I got totally involved in. Writing in machine
language requires the Components Reference Manual which describes the complete
instruction set in detail, and has a table in the back for creating the
punch codes necessary to manually create an IPL-format card. It is a bit
tedious, but without an assembler, there wasn’t much alternative. Small
programs of only a few bytes can be entered through the dials on the front
panel with the right settings in the CE panel, but that’s
it. The 5496 Data
Recorder made it easier by allowing you to combine 1, 2, 4, and 8 bits in a
single character, and it would figure out which character the value mapped
to, so that made it easier. I began writing an assortment of cute one-card
programs, beginning with strings of halt instructions that made the lights
on the front panel do funny things, and some that were more useful, like
one-card versions of many of the utility programs that IBM provided with the
System/3.
I also wrote some utilities that weren't supplied by IBM, like a one-card
"gang punch" program that read a card containing punch
data, then 4 more cards containing print data (one card per print line),
and then punched and printed all the accumulated data onto as many
cards as followed, until the hopper was empty. With all my ambitions for
future programming projects, writing everything in machine language and
converting the values into the card characters got tedious, and I wanted a tool
to help.
So I wrote a hex-to-IPL conversion program that read 2 cards with hex values
and punched 1 card with the converted IPL characters. I wrote it in
machine language, by then my preferred coding "language". A friend of
mine wrote the same thing in RPGII.
It was very interesting to notice the contrast. His program was in a card deck
over an inch thick, and mine was about a quarter of an inch thick. His
read 2 cards, and turned on the processor lights (which showed addresses and
such, showing how busy the computer was) for a second or so before
punching the card. Mine just read the cards in and punched the card out as fast
as the MFCU could work, not even getting the
processor lights to glow at all. At first I thought it was a bug, but when I
examined and tested the output card, I realized that there was no bug. I
had just written code that ran very fast, without any of the overhead of the
RPGII model! Once I had that program working, I used it to create several
more programs that I wanted to write; I had a long list of tools I wanted to
create and fun things to experiment with.
It wasn’t long after that that I created my IPL-to-Text converter that reads a
card in IPL format and punches it out as a text card so the
6-card Absolute Card Loader can read it in. I wrote a few larger programs,
all in machine language, that required multiple cards.
Most of these I wrote in IPL format (with instructions on each card to load
part of the program into memory and then branch to it) and in text card
format so the Absolute Card Loader could load it. A few years later, working at
a company with a larger System/3, I wrote the most ambitious RPGII program
I'd ever written, to parse RPG II source code and produce a series of
statistical reports on it.
I lost the cards for it, probably because I moved all the cards to disk and
didn't bother with maintaining the cards after that. It was easier to work
on it as a disk-resident program, but I never made arrangements for
transferring it off to another form of media, so all I have is a
photocopy of the printout.
2010
That was back in the late 70's. Now, fast-forward to the present, 2010. I neglected
to transfer all my cards to disk and then to tape, so that I might
eventually be able to move them to my own computer. I delayed too long, and the
System/3 shops and any others that might have been able to read 96-column cards were
disappearing fast. I made several unsuccessful attempts to get these cards
transferred to PC-readable format, until I found the Wikipedia article
"IBM System/3". I read it and was impressed with how detailed and
accurate it was.
At the bottom was a link to a website describing a System/3 installation in New
York. I emailed the site's owner, asking if he could read my cards. He
could not, but referred me to Henk Stegeman at this website, who was able to
complete a project he'd been planning for a while, and then he could. My
search was over! Once he gave me the green light, I sent him 2 boxes of cards
with all my hard work in them. A couple of weeks later, I had all my cards
read into .txt files that my computer could read! It was interesting to notice
the contrast: 10 days to ship the cards, just a couple of
minutes to email them back to me; 2 boxes of cards (4000 cards) shipped, and
all the cards fit into a .zip file not even 100k! While waiting for
the cards to be read, I began work on a suite of tools that would be able
to process the "cards" once read to a flat file.
The tools included code to read cards to binary from both IPL format and
text-card format, a hexadecimal dump tool with literals in both ASCII and
EBCDIC, a powerful disassembler, and a script-parser to drive them all.
As of this writing (July 2010), this is still a work in process and isn't ready
for public consumption yet. Once I had the disassembler working quite well
(much better than the Mnemonic Dump program that IBM supplied to the Field
Engineers), I decided to make the leap and build on the disassembler to
create an IBM System/3 simulator. I began work on it, and after just a couple
of weeks of evening and weekend time, I had it working. I’ve named it “Symulator/3”.
I first got it to run some of my one-card programs, then the Absolute Card
Loader, and finally I tried it on the compiled RPGII programs I had, PowerOfTwo and TrigTables.
After fixing a few fairly minor issues with the simulator, I had both programs
running! This was the realization of a dream of mine from high school of
having my own System/3! Of course, my System/3 was a lot smaller, a LOT faster,
and took only a tiny fraction of the power that the real machine took. It
also runs a lot cooler and is very portable.
One of the most amazing things that I noticed was the speed of the simulator,
written entirely in C# with Microsoft's .Net framework. I thought that the
overhead of .Net would slow things down as much as the new hardware (3GHz
Pentium) would speed it up. The C#
source code for Symulator/3 is available on GitHub.
I decided to test the speed with the one-card clock program that my teacher
finally gave to me after I'd written my own version of the same thing. It
ran so fast that I thought there might be a bug in my simulator, so I carefully
counted the repetitions of the instructions that the clock program used to
take up a full second, and discovered that the simulator was working just fine.
Instead of taking 1 second to get through the loop in the program, it was
taking around 20 or 30 milliseconds! Even with the overhead of Windows and the
.Net framework, and of the simulator, this thing was moving incredibly
fast. I'd really lost sight of how far things had progressed since the early
70's.
The
Components Reference manual states 1.52 microseconds per memory fetch, which
works out to a clock speed of just under 658 kHz. Very impressive considering that the previous generation of
computers, the IBM 1401 had a clock speed of around 87 kHz, and the ENIAC ran
at 5 kHz. The ENIAC was an amazing
machine in its day as it did in 30 seconds calculations that took 20 hours to
do manually. In theory, the System/3
could do them in less than a second.
1970
I'm quite amazed with how much I still remember about the IBM System/3. I've
almost completely forgotten everything I learned about other computers I
worked on between the System/3 and Windows. I worked on the Honeywell Level/62
and the Hewlett Packard HP3000, both of which I wrote some interesting
tools for. I did some machine language programming on the HP3000 and wrote a
couple of technical articles for it, yet that stuff has faded from my
memory while the subtle details of the System/3 remain surprisingly clear. What
follows is a summary of some the things that I still recall with great
clarity.
When a program is first loaded, the machine reads cards in IPL (Initial Program
Load) format, beginning at memory address 0x0000. In this format, each
column of the top tier is combined with 2 punch rows from the bottom tier to
form an 8-bit byte, and the middle tier is combined with 2 more punch
rows, so that each card contains 64 bytes of 8-bit-per-byte binary data.
The first six cards contain the loader in IPL format, which is as much of an OS
as the card machine had. The loader loaded itself into the bottom 256
bytes of RAM, and after it had been loaded, control was passed off to it
and the loader then read the cards that follow in “Text” format, in which 4
punch columns are compressed into 3 binary bytes by means of a very
well-engineered data management algorithm. It transformed 4 x 6 bits BCD into 3
x 8 bits binary.
The text cards began with the character “T”, and the last card began
with an “E”. This last card has a different format that instructs the
loader to branch to the entry point of the program it just loaded. I still
remember this because I bought the manual on the loader and reverse-engineered
it to so I could write a machine-language program that would read an
IPL-format card and punch out a text format card. I was really proud of that
program.
I was getting ready to write my own assembler, but other things got my
attention and I never got started on that project. The last card with the “E”
also contained a short routine for displaying data in memory somehow. I
never used it so I don't know anything about it. There was also a 9-card
relocatable loader that would load and then halt to prompt the operator to
dial in the address at which to begin loading the program. Once the user had
entered an address, the loader would then load the rest of the program.
The 6-card loader always loaded each card's data at the address specified in
the card.
The relocatable loader would add the address value entered by the user to that
address, and then load each card's data to the calculated address.
It was supplied with some of the IBM programs for the Field Engineers to use,
like the Mnemonic Dump program (disassembler) and Trace (sort of like
Microsoft's early non-GUI debugger for C and assembler debugging). Trace would
single-step through a program, displaying the register values affected by
each instruction. Once a program ended, the next program was run by placing the
cards into the primary hopper, and pressing “Program Load” on the front
panel, which initiated a boot all over again, reading the first card in IPL
format into memory address 0x0000. Each card program had the same first 6
cards, which were the loader. In essence, each program was its own OS, and
each program was run by booting the system. Without a disk drive, there wasn’t
any place for the OS to reside.
Memory was not reset by pressing either “Program Load” on the front panel or
“System Reset” in the CE panel. Either button would abort any program
running at the time, but “Program Load” would also initiate another boot. Since
memory wasn’t disturbed by either button, core dump programs could be run
to do a post-mortem exam of a failed program. Each compiled RPGII program was
self-contained in a deck of cards, and had all the instruction code necessary
for handling I/O and assisting the user in recovering from any errors that
might occur, essential for a card-only system.
The card system OS was a very interesting thing. Since there was no
continuously available online storage on a card system from which the
OS can be refreshed, the OS was only in the compiled programs, but they
required some initial values to be present in memory.
When the machine is first powered up, its memory is blank. The first thing that
needed to be done was to run the SIP, System Initialization Program. The
SIP is not a program loader or an operating system, just a program that runs to
completion and halts like any other.
I reviewed the System Control Programs Logic Manual and determined that the
System Initialization Program performs these tasks:
1.
Initializes the system date, storage size, and chain image from
cards
2.
Initializes the copyright area to blanks
3.
Initializes RAM to blanks from the first byte after the program
image to the highest address as indicated in the card input
4.
Gathers & records error data captured by the IOCS (for any
programs run after power up and before SIP was run).
I
wrote a little one-card SIP sets the memory size and printer chain image in
memory. I used the smaller 48-character chain with all capital
letters, which is the image that was used at the high school.
The other chain image was a 120- character image, which is more characters than
in the card character set. On a system without a disk, each program runs
to completion, then finishes with a Halt instruction that illuminates the 2
7-segment displays on the front panel with a code that indicates the state
with which the program ended. “EJ” was the halt display that
indicated that a program ran successfully.
It stood for “End of Job”.
The RPG II compiler occupied
2 boxes of cards, at 2000 cards per box. The first box contained the code that
parsed the source code, performed diagnostics on the source code,
determined whether the program could be compiled, and built a symbol table in
memory for the second box's cards to use to punch out the program
code.
The compiler existed not as a huge single program, but as a series of small
programs, each tailored to perform a specific step in the compilation
process.
One stage read in the source code header card. Another read the file
specifications and others read in the other sections of the source code.
Other sections performed various diagnostics and were responsible for printing
out specific warnings and errors.
The cards in the second box worked the same way, and each section was
responsible for punching out various parts of the object deck, like the
6-card loader, the card and printer I/O routines, and various parts of the
compiled code.
Except for the last sections in each box which ended in one halt or another,
each section ended by initiating the load of the next section.
It was a very cleverly implemented system that worked very well within the
limitations of a card-only system with only 8k of RAM.
Greg.