Ramblings of an
old assembly hacker:
Back in the old
days, before the earth cooled and all that, when men were free and 16K RAM was
a goodly chunk of memory, I found myself hacking on an Interdata 16 mini
computer.
This machine was
about the size of a stereo amplifier and was rack mounted into a thing the size
of a small refrigerator. It had 16 K of memory, which was core memory back
then, meaning a bunch of visibly large magnetic rings with little wires running
through them that could flip or read the magnetization. You could plug in 4 of
those boards to boost the thing up to 64K which was all you'd ever need (and
because the processor was only 16 bits it was also all you'd ever be able to
address without getting into bank switching).
Now don't get
confused by looking at a modern day (1996) PC. This little stereo sized box was
not the case that held the processor, the memory, the floppy disk drive, the
CDROM drive, the sound card, the video display adapter and the 1 gig hard
drive. In the time frame I am talking about (1975) hard disks were the size of
washing machines and held about 70 Meg. Floppy disks were 8 inches across (and
held about 30 bytes as I recall). CDs hadn't been invented. There were no sound
cards and at least the box I was hacking on had no video. The box was just
processor, memory, 16 lights (to show whether the bits in a 16 bit word were on
or off) and sixteen toggle switches (so that you could set the bits in a word
to on or off).
The only
peripherals that we had attached were a teletype (yeah, one those thing that
actually slammed a print head against an ink ribbon at a whopping 10, count '
em, 10 characters a second) and a fan fold paper tape punch/reader. Mass
storage meant punching your bits into a piece of paper tape which you could
later read back into memory.
-INTERUPT-
Before we get
too much further in this jog down memory lane, I was once overheard telling
some of these stories to a compatriot in one of the Microsoft cafeterias, and
the person overhearing leaned over and said, "Yeah, Yeah, my dad used to
tell me how he had to trudge 16 miles to school each day through the snow. You
old-timers are all the same..." I was shocked. He had missed the point
entirely. I was not telling a story about what a miserable impoverished existence
I had had back in the old days. I was not describing hardship. I was describing
joy. I thought I had died and gone to heaven. I had some fool paying me money
actually giving me cash to spend all day at Disneyland riding on all the rides,
playing with these neat toys. I was only describing the state of the world back
then so that I could describe what I considered one of the supreme hacks of my
life. It would make little sense to someone in today’s world without a little
history.
I just did not
want you to be confused as to my attitude toward those little insignificant
machines. They were the first ones I hacked on, and like a chick coming out of
the egg and imprinting "MOTHER" on the first moving thing it sees,
those crummy little boxes just make me sit up and SMILE.
-END OF
INTERUPT-
10 characters a
second is SLOW. Oh, it is a little faster than you can type, but just barely.
(60 sec * 10 chr/sec / 6 chrs/word = 100 words/sec, a fast typist but not
beyond human capabilities). You didn't edit code by pulling it up onto the
screen from the hard disk and zooming around with your cursor making changes
here and there. Instead you sucked a paper tape through the machine to load the
text editor (only a couple minute process) and then with your paper listing in
front of you, you would ask the machine to show you line number 145, and you
could type in some changes to that line. Then you would pencil in the changes
you had made to your listing (because at 10 characters a second a fresh listing
was perhaps a 2 hour chore). After you had made the changes you wanted, you
would punch a new tape with the changed source program. You would lean over to
the front panel, check that the loader was still present in high memory, mount
the tape for the assembler, run the loader to suck it through, overwriting the
text editor. Then you would mount your source tape in the reader and again from
the front panel you would run the assembler, which would read in your source
tape and punch a machine code tape.
Of course, if
there were errors, like a typo, you got to restart the whole process, so you
were VERY careful not to make careless mistakes. Once you had the machine code
tape, you could mount it, run the loader from high memory to suck it into RAM
and then run your program. You could either run it in single step mode, where
you could watch the 16 lights light up to show you which machine word you were
on or you could just smoke it and see if it crashed.
Just as an
aside, since the only feedback you got from the machine when stepping through
the code was the 16 lights showing the machine instruction you were on, it did
not take long to memorize most of the machine codes. You knew that a C86F (what
you see on the panel is lights in binary on and off in the pattern 1100 1000 0110
1111 and you pronounce it in hex "Charlie Eight Six Fox") was a move
instruction from register 6 to register Fox. In fact, since it was such a pain
to go through the whole edit process I just described, and since you had all
the machine codes memorized it was far easier when debugging to simply flip the
switches and punch in a little patch of code right into memory than it was to
change the source. (Of course, you would pencil the patches onto the already
highly penciled listing and hope you would remember to include it on the next
actual edit pass.
Now, there was a
problem associated with just smoke testing the code you wrote (smoke testing is
where you just let her rip and see if the thing catches on fire and burns down)
and the problem was this; occasionally when your program ran wild, it would
overwrite high memory where the program loader was. This was a royal pain when
it happened. The program loader was not large, about 300 bytes. (not 3Meg, not
3K, but 300 bytes) BUT without having that in high memory you could not load
any other chunk of code into memory. So how do you get the loader into high
memory to begin with? You guessed it, you enter it in from the front panel
switches, one byte at a time. A royal pain indeed.
As many times as
I had to enter it in, I never did memorize this random string of 150 4 digit
hex numbers so it involved reading down this page of numbers, translating each
one into binary, setting the toggle switches, pushing the enter button ... And
of course, if you made a single mistake, the loader would not run. If the
mistake was that you entered a number wrong, then you would track it down and
reenter that one, but if you accidentally omitted a number, or wrote one in
twice, everything after that point in memory was in the wrong place and had to
all be reentered.
There was no
battery backed CMOS or any ROM in the system, there was just nice overwriteable
core memory and if you overwrote the wrong portion you had to reenter the
loader by hand.
While poking
around in the instruction set for this fine machine one day, I came across a
bulk load instruction that would read from the teletype tape but for obscure
reasons (beyond the scope of this flashback, in fact beyond the scope of my
failing memory) it could not read from the paper tape punch/reader. This thing
would turn on a device, go into a sense status loop and read bytes from the
device plopping them down into consecutive memory locations. It was just the
thing I needed. Using this one instruction I could write a SHORT tiny loader
(about 5 words long) that would load the real loader into high memory. Or so I
thought.
It turned out
though that the paper tape that came in off of the teletype had a problem which
was that it did not give you 8 bits of information, it only gave you 7 bits.
Sure enough my tiny little boot loader could plop the bytes down into memory,
but the high bit of each byte was 0. Thus it was impossible to write an
instruction like C86F because the C requires a high bit. This meant that I
could not read a MOVE instruction from the teletype and the loader was full of
move instructions. However, since I had by then memorized the instruction set
of the machine in binary, I could in my head imagine which instructions I could
read in from the teletype. "Let's see, I can do add instructions but only
into an even register ... No word moves, but I can do byte moves from odd
registers into even registers ..." Was it possible to write any working
code using that oddly restricted subset of all the machine instructions?
Of course I
wouldn't tell this story if it had been impossible. I wrote the peculiar loader
in this code subset and the whole process ended up working like this. You would
key in 5 instructions into low memory, mount the special boot tape into the
teletype. The five instruction program would read the intermediate loader (the
one written in the crippled instruction set) from the teletype into middle
memory. Then the 5-instruction loader would jump into the intermediate loader.
The intermediate loader, written in the funny subset of the machine codes was
smart enough to continue reading from the teletype, but knowing that every byte
coming from the teletype had only 7 bits, it would chop them up, taking a good
nibble (4 bits) from each, glue them together into complete 8 bit bytes and
stuff them into high memory, assembling a nice completely correct copy of the
REAL loader.
It was totally
cool. Now instead of having to type in 300 words, you just typed in 5, put in
the special tape and were off and running. Well, were off and running most of
the time. Sometimes the system would just hang. How it is possible to get a bug
in a sequence of 5 instructions I do not know. Clearly the hardware of the
teletype could get into some state that the autoload instruction could not get
around. You just powered everything down and hoped that you could run it when
you powered up. It never was a guaranteed thing. Because I could never get it
to run flawlessly my boss would not ship it as a product to our customers.
However this was
a small company, about 30 people and our customer base was small, measured in
the hundreds, and not only did I do programming back at the home office I also
occasionally was called on to do field service. I would show up at a customer,
they would have the loader keyed into memory, we'd be running our special
testing software. I'd be demonstrating how it all worked. Something would go
wrong and the customers would quickly from the front panel check to see if the
loader looked intact up in high memory, "Damn it. It's been trashed, gotta
key it in again from scratch."
"Just a
second," I would say. I'd whip out my magic tape. Type in the 5
instructions, SLURP and loader was up in high memory again ready to go. They'd
look at me with wide eyes. "We want that magic tape!" I'd have to
explain to them how it worked and why my boss would not let me sell it to them.
You could see in their eyes that they were considering the option of killing me
on the spot for that magic boot loader tape so I would always say, "Hey, I
didn't show you this tape. You've never seen it. You will never call us for
support since it is not a product. Seems to me if you invent this process on
your own and save yourselves some time inputting in the boot loader that is
none of my business. I have to go to the bathroom now. I'm gonna leave that
tape in the machine and I guess I'll never know if you make a copy while I'm in
the can. wink wink" I never saw such big smiles as I went off to take a
leak.
I don't know if
any copies were ever made of that tape. We certainly never got any calls about
it from any customer ever, but I did notice that those customers always asked
for me when they needed any service from then on.
Perhaps in this
day and age of hot and cold running water it is hard to imagine the pride of
the guy that invented using a bucket to carry water from the stream instead of
just cupping your hands and making a hundred trips, but that is how I felt.
Since that time,
I went on to do lots of systems hacking including a 13 year stint at Microsoft
in the early days. The theme was always the same, "How can you make it
less work for humans to use these damn machines and how can we get around the
all these miserable incompatible hardware problems?" GDI, the graphics
subsystem of Windows that I developed, has certainly impacted more lives and in
any real sense was a more important chunk of code, but it never produced the
thrill that I got from piecing together in my head the binary machine code with
no high bits that would serve as the intermediate loader.