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.
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.
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.
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.
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).
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.