Wednesday, April 25, 2007

Homeless in the 21st Century

It's now the interim period between the end of my NASA internship and the beginning of my summer research fellowship. I find myself - once again - homeless, while I wait for my housing to become available for the next semester.

As a college student, this happens to me three times a year; the transitions of the fall, spring, and summer semesters drive also the availability of housing for college students. Whether it be the dorm kicking everyone out for two weeks between semesters, or campus apartments unwilling to extend a summer lease past August 9th when I can't move into fall housing until August 23rd, the gaps between semesters are not a vacation but a hardship for those of us who don't have anywhere else to go during those times. My parents would be willing to take me in, but they have such a small house that there isn't a bed for me to sleep on there. So in the interim weeks between semesters I become a modern gypsy, taking my car from place to place and staying with friends until my welcome runs out.

This semester is not too bad. One of my professors has kindly allowed me the use of his spare room, and we get along well. I am experiencing no physical hardship - only the mental anguish of trying to define home and coming up empty-handed. I have been provided a house to stay in, and hospitality, but it is not my home. In my heart, home is with my fiancee Melissa, but neither of us has our own place. Last semester, Melissa's week consisted of bouncing from Weatherford, to Edmond, to Norman, depending on where she needed to be for college or work. When we are married we'll have a home together, but for now we make do as best we can.

I drove to Weatherford today, but my professor happened to be out, and I felt funny about going into his house alone. So I picked somewhere far away and drove there until he would get back. It's times like this that my car means more to me than just transportation. It represents freedom, and a much needed piece of the familiar in unfamiliar lands. As long as I am rushing 78 mph down an unending stretch of freeway at least I am somewhere, doing something, which is infinitely better than nothing, nowhere.

Friday, April 20, 2007

Gun Threat in the NASA Building I Work In!

Hot on the heels of the VT shooting, everyone is on edge. Now there has been a report of a gunman at the building I work in on the Johnson Space Center!

On Friday mornings I do a teleconference meeting from home. Today the conference ran late and made me late coming in to work. I was just about to head down to the Johnson Space Center to go in to building 44 to get the paperwork I need to check out, when I got a call from a coworker. He said there was a man with a gun and security is on lock down!

I don't really have much more information than that yet, and what more I have heard so far is unconfirmed so I will not start any rumors with it. But it's just crazy; I mean, I work there! Let me tell you that Building 44 is not the place I would have in a million years expected to see this happen. It's been the most stress-free work place I've seen, and I can't imagine what would push someone over the edge.

Update: They have helicopters showing the building on the news on CNN. Unreal.

Last Day of My NASA Internship

It's been a busy week since my last blog entry. Fear not, dear reader(s), I have not abandoned you. I'll have more time to write next week, including some entries about how my internship went. And will they ask me to come back? I'll find out next fall.

Friday, April 13, 2007

Reading: Zero

My sister mailed me the book Zero: The Biography of a Dangerous Idea. The book has already used four of my favorite words, and that's just the title! Zero is my favorite number; I like biographies, and I like dangerous ideas best of all. I can't wait to start reading it.

Thanks Rose!

Start Your Own OS Project in 30 Minutes

Have you ever dreamed of writing your own operating system? The first step is to get a kernel loaded. It's easier than you think. I'll show you how.

If you took an operating systems course in college, unless you went somewhere like Berkeley or Vrije in Amersterdam, it's likely that there was not a professor in your whole university who knew how to write an OS kernel from scratch and get it to boot by itself. Look, they're only human, ok? - most programmers wouldn't know how to do it. But it also means you came away from that class vaguely dissatisfied. Because if you take an operating systems class and never write your own simple kernel, it's like taking a driver's-ed course without ever getting to sit behind the wheel.

It's time we changed how we teach operating systems. Let's get started.

The first hurdle to overcome is getting the BIOS to boot your code. There are 512
bytes of code at the beginning of a disk, which the BIOS loads and executes. This is called the boot sector, and it is the responsibility of this incredibly tiny program to load other code and finally the actual kernel.

My first intention was to write one of these boot sector programs, because it would be a way to get code running on the machine completely by itself. There is just enough space in 512 bytes to write a very simple program. But that doesn't sound very useful, and besides, it's been done before.

So I wanted to contribute something new. Besides my idea of putting a toy operating system in the boot sector not being original, there is already a perfectly good boot loader program available. It's called GRUB. Why not put GRUB in your boot sector instead of custom code, and use GRUB to bootstrap your prototype OS? Suddenly what would have been weeks slogging through nasty bootstrap code isn't necessary. Things are looking up.

GRUB stands for GRand Unified Bootloader. If you dual-boot Linux and Windows, you may know GRUB can load your favorite operating systems, but did you know there's another reason it's called Unified? The people who developed GRUB looked at all these operating systems floating around; they all need many of the same things to happen as they boot, but each implements their own proprietary boot loader. They said, "What if there were a universal standard for booting an operating system? Then we could write one really good boot loader that would suffice for any operating system." They did.

What they came up with was the Multiboot Specification. It's a magic header that you include in a program to tell GRUB the information it needs to know to load your kernel. GRUB is smart enough to read a file system, so you don't even have to place your kernel in specific sectors or make some kind of wacky system file. Instead, all you have to do is compile a program as you would normally, and you can place the ordinary program file in any directory on the disk.

In an article I read recently, Julio Vidal describes how he made NetBSD Multiboot-Compliant. The article includes a detailed description of the boot process, and is an interesting read all around. Most importantly for us, though, the article links to some example code, from the GRUB documentation, which shows how to make a minimal kernel that is multiboot-compliant.

You can find that example code here: http://cvs.savannah.gnu.org/viewcvs/grub/grub/docs/#dirlist

Don't worry, you don't need all the files listed on that page - just three of them. You need boot.S, kernel.c, and multiboot.h. In order to illustrate the proof of concept (that, once loaded, I can run any code I want), I made a slight modification to the files which simply displays my own custom message after the kernel boots. You may want to work with the modified version in order to see where to put your own code, and because it is the version I used for these instructions, although the unmodified files should work too. You can get them from my downloads page: boot.S | kernel.c | multiboot.h

Now that you have the code, you need to compile it. For this, you will need to be running Linux. You'll also need Linux for the later steps involving GRUB, so you might as well get it now if you don't have it already. I recommend Ubuntu. Ubuntu comes on a Live CD, so you can run it from the CD without even having to install it. You can also install Ubutunu on an external hard drive or even a USB memory stick. (I will be posting another blog entry soon explaining how I did that.)

Compiling the code is the second major hurdle to cross. Most C programs link in libraries for things such as I/O and debugging. These C libraries in turn depend on an OS, or more specifically, they rely on making calls to the kernel of an OS. Well hold on a minute - we haven't got a kernel yet; that's what we're trying to make. Not only can we not rely on the the standard libraries, we have to make sure the compiler doesn't sneak external references in anyway (which it will try to do if you let it). So we have to use special compiler options to force the compiler to generate code that stands alone and has no external dependencies.

Open a terminal in Linux and type:
cd /whatever/directory/you/have/the/code/in

Then use this command (all on one line) to compile it:
gcc boot.S kernel.c -o mbs-kernel -ffreestanding -nostdlib -nostartfiles -fno-stack-protector

Explanation:

  • -o mbs-kernel: names the output file
  • -ffreestanding: means the resulting program should have no dependencies
  • -nostdlib: tells the linker not to bring in the C standard library, which won't work in the kernel
  • -nostartfiles: tells the linker not to bring in any C startup code
  • -fno-stack-protector: is a fix for the error "undefined reference to '__stack_chk_fail'"

This produces the file "mbs-kernel" which contains our new kernel.

You may need to be root to do the rest of the steps. To switch to superuser mode so that you can run all the commands, type:

sudo su

...and provide the root password when it asks.

Next we need to install grub to a floppy disk so that we can boot from it. It is possible to use a USB key instead, but I haven't figured out how to do that yet. So we'll use a floppy disk for this example.*

Open a terminal and type the following command:
grub --batch --device-map=/dev/null <<EOF

The above command starts GRUB in batch mode. Insert a formatted floppy disk and type these commands to install GRUB to it:

device (fd0) /dev/fd0
root (fd0)
setup (fd0)
quit
EOF

If you are using a USB external floppy (what I was using), then the device will be different. In that case, do not type the above, but use this set of commands instead:

device (fd0) /dev/sdb
root (fd0)
setup (fd0)
quit
EOF

USB floppy drive devices show up as /dev/sda, /dev/sdb, etc. Mine was sdb because I also have an internal SATA hard drive, and that occupies /dev/sda, so the floppy became /dev/sdb. If you have an ordinary IDE hard drive, then a USB floppy might be /dev/sda. How can you tell which one is your floppy disk? What I did was I used the Gnome file manager to mount the floppy disk (by double clicking its icon). Once I could see the contents of the floppy disk in the GUI file manager, I knew it had to be mounted. Then I opened up a terminal and typed:

mount -l

That's a lowercase "el". It caused mount to list all the mounted file systems - I looked at the one that matched where my floppy was mounted and the device given was the device I used for grub. However, if I recall, the drive has to actually be not mounted for the GRUB install to work. So after you mount the disk to find out its device file, be sure to right-click on it in the file manager and select "unmount" before you attempt to do the GRUB install.

Now that we have GRUB installed, we need to put our compiled kernel onto the disk. Use the file manager to mount the floppy drive and copy the file mbs-kernel to the /boot directory of the floppy disk.

*Note: If you already have GRUB on your hard drive, you don't necessarily have to have a boot floppy at all for this exercise. If you are comfortable with the idea of changing the boot configuration of your computer, you can safely skip the GRUB floppy install steps above, and place your homemade kernel directly in your /boot directory on your hard drive next to your Linux kernel. When you boot, you can choose whether to load Linux or your own kernel.

The last step is to modify the menu.lst file to make an entry for your kernel. If you have put your kernel on a floppy disk, you should be able to go to /boot/grub and double click on menu.lst in the file manager, which will open up gedit and let you edit the file. If you are going to run the kernel off your hard drive, you will find that gedit cannot save menu.lst if you opened it by double clicking. This is just a security precaution by Linux - the file manager didn't run gedit as root when you double clicked the file, so it can't write to it to save your changes. No matter - you can easily start gedit from the superuser prompt, and then it will have root priviledges. Just type:

gedit /boot/grub/menu.lst

Or, if you're back at the $ prompt instead of #, type:

sudo gedit /boot/grub/menu.lst

Menu.lst is simply a script that GRUB reads to know what boot menu options to show and how to execute them. At the very bottom of the file, if you are using a floppy, add the lines:

title Multiboot Kernel Example
root (fd0)
kernel /boot/mbs-kernel

If you want to boot your kernel directly from your hard drive, put the file mbs-kernel into your /boot directory on your hard drive, and add this to the bottom of your menu.lst file in /boot/grub/menu.lst:

title Multiboot Kernel Example
root (hd0)
kernel /boot/mbs-kernel

Once you have prepared the disk, reboot your computer. If you are booting from a floppy, make sure your BIOS is set to be able to boot from the floppy drive. Some computers have a key you can press to get a boot menu and choose manually. GRUB should start up when the computer boots. Choose the Multiboot Kernel Example, and GRUB will start your kernel. If you were successful, you should see either:
  1. A screen full of gobbledygook if you booted the default GNU example code
  2. A friendly message if you booted my version
If you get a message from GRUB that says "Error 28: Selected item cannot fit into memory," that error message is badly worded. It really means, "Default load address is too high." I got the error on a machine with 32 MB of RAM, but not on one with 256 MB. This problem could be fixed by instructing GCC to compile the program for a lower memory address. Anyone know how to do that?

In any case, as soon as you get the kernel to boot, you should immediately boot back into Linux, delete my code changes, and add your own code instead. This is your kernel.

If you want to go further, here are some resources:

http://www.cs.utah.edu/flux/oskit/
http://www.osdev.org/wiki/Main_Page

Remember, you are starting with a blank slate. You won't have a filesystem driver, I/O, anything, until you put them into your OS. You are starting at the bare metal. One way of looking at it is that you have nothing holding up your code.

Another way of looking at it, is that you have nothing holding you back.

Happy hacking.

Thursday, April 12, 2007

Now I Have a Home Page Too!

Come see it at: http://system.windows.codeslinger.googlepages.com/home

This blog meets most of my needs, but I'm finding more and more cases where it just isn't enough. For instance, I want to include source code file downloads with some of my articles, and there isn't an easy way to do that through Blogspot. Fear not; my new web site does not replace this blog. I will be using my home page and the blog together.

I had been thinking about making a home page for quite a while now, and went to look for a paid web host tonight. I was just thinking, man, I wish Google did homepages too. That's when I stumbled upon http://pages.google.com/. Wow! My main concern when looking for a web host had been finding a site I can trust, and in that category Google definitely fits the bill! Since I already have a Google account, I had a page already waiting for me.

You really have to see the AJAX web page editor Google has come up with. It blew me away - working with it is like working on a Macintosh. Who needs the Windows desktop when javascript applications running in your browser have now surpassed traditional desktop apps in quality of service?

Anyhow, take a look. I'll have to warn you, I don't really "get" web design. So I will be keeping the site clean and simple to cover up the fact that I don't know how to do fancy. In the movie Walk the Line, when June Carter asked him how they get such a steady sound, Johnny Cash's character just looks sheepish and says: "Well, we'd play faster if we could."

Wednesday, April 11, 2007

NASA Procedures: In Case of Emergency, Save the Icecream

Working at NASA has been a great experience for me. It is an engineer's paradise. It is also - I might remind you - a government operation. If you've been in the military or civil service, you'll understand what I mean; in a government job, normal rules of logic and common sense are still there, but they undergo a bit of a twist, like light passing too close to a black hole. I'm not saying it's good or bad. All I'm saying is that things can get rather amusing sometimes.

We have a very high-tech Coke machine in the building I work in. It has a glass front so that you can watch what it does. Instead of just dropping your coke down a chute like a normal Coke machine, this machine has a conveyor belt that moves up and down like an elevator. In order to retrieve your beverage, the machine first moves the conveyor up to the "floor" that your drink is on. The bottle (which is stored upright) is pushed onto the conveyor. Then the conveyor belt moves the bottle sideways until it gets to the end of the belt where it enters - would you believe - a chute. It's fascinating to watch when it works, but the machine is often out of order. You see, the chute is only wide enough to accept an upright bottle coming off the conveyor. The entire machine was built on the assumption that the upright bottles would never fall over. Once a bottle does fall over (which is inevitable) the machine cannot get it off the conveyor belt, and other people's purchases pile up behind it. The Coca-Cola service man has to be called every time a bottle falls over on the conveyor.

No longer a dispenser of beverages, today the Rube Goldberg Coke machine stood there, with it's conveyor jammed with bottles, as an ironic monument to overengineering. A warning, if you will, to anyone who might forget the K.I.S.S. principle.

I joked about this with one of the NASA oldtimers I work with, and he followed it up with an interesting anecdote. That's nothing, he said. A while ago we used to have an upright ice cream machine. Any time the power went out, the ice cream bars inside would melt, and gallons of vanilla ice cream would drain to the bottom of the machine and out the hole in the front. It made a terrible mess in the hallway. Eventually, something was done about it:

The building I work in is packed with radio and computer equipment, so you can well imagine that any loss of electrical power is a big deal, as equipment has to be shut down properly if possible. For this reason, we have a written procedure that is followed when loss of power is imminent, to ensure that every important piece of equipment is taken care of.

I have it on good authority that, for many years, step one of the emergency power loss procedure read:
  1. Call the Bluebell Icecream company.

Saturday, April 7, 2007

Looting CompUSA

I woke up this morning to feel an unexpected downdraft of warm air. Wait - is that the heater going? Holy crap.

This is bad because I'm allergic to certain house dusts, and the heating system seems to be a source of that kind of dust. I always get sick if the heater is running. Normally I would have the vent closed to prevent the allergens getting into my room, but until yesterday it was quite warm, and I can have the vent open for the A/C without ill effect.

I had heard a cold front was coming, but I can't believe it came as far down as Houston, and got as cold as it has. It triggered the heater, and now thanks to my allergy I have a case of the crud and a sore throat to keep me company for the next few days.

Despite not feeling well, I went ahead with my favorite Saturday pastime, which is to hit up the electronics and computer and book stores in order of their closing times. First I go to EPO electronics until they kick me out at 5 pm, then I wander CompUSA like a friendly ghost until they kick me out, and then on to Barnes & Noble which caters to night-owls and has a Starbucks to boot.

After reading about a foxhole radio made from a slinky, I decided I want to build my own radio (though not out of a slinky). Some of my most memorable electronics experiences involved building crystal radios and one-transistor radios from Radioshack kits when I was a pre-teen, but ultimately I became frustrated with the radios' unpredictable behavior and changed my focus to digital logic instead. I now realize that most of the unpredictability must have stemmed from my poor understanding of necessities like proper grounding techniques and controlling parasitic capacitance. With the experience I have now, I figure I could build some much better receivers and have some fun with it again.

That's why I went to EPO today - to get parts. EPO is a giant electronics store in south Houston. Like Radio Shack used to be but much better. It's an electronics geek's dream - they have components, kits, tools, testers, surplus junk, everything. It's like walking into the pages of a Digikey catalog.

I was surprised to find that they don't carry crystal radio kits. Not one. I guess nobody builds them anymore. Shame. They do have some other radio-related kits, but not what I was looking for. They also had a confusing array of ham-radio kits, but I'm not licensed to transmit ham radio and I wasn't sure which receiver to get either.

I was intrigued by a phase lock loop experiment kit they carry. It uses a digital phase lock loop chip (PLL) and a PIC microcontroller to give you a push-button, digital control over what frequency is generated. It was meant for sending, not receiving, but I thought, what if I run the output of an antenna amplifier (also available as a kit) into the phase lock loop chip? Then maybe I could make the PLL lock to a radio station by typing the station's frequency into the digital control.

It's a hell of an idea but the cost quickly got out of hand. The PLL kit is already expensive, and the antenna amplifier was downright overpriced for something so simple. Then I realized I needed some sort of "mixer" chip to compare the PLL output back to the antenna input, in order to skim the actual sound off the incoming signal. (The PLL locks you with the phase of a signal but the actual sounds of AM radio come from the signal's amplitude.) I found a general-purpose IF mixer chip that looked perfect for the job, but it was expensive too. I was expecting to spend, say, $35 tops today on a weekend project. Instead I ended up with an armload of parts that came to $90 and I didn't even know if the circuit would work or not, it was just based on a hunch!

I would have loved to test the idea, but I also need to be more careful with my money. Not to sound arrogant by comparing myself to the great man, but I live like Nikola Tesla did. I'm chronically broke, spending money on inventions instead of food. I'm trying to get away from that. When the items rang up to three times what I expected, a glimmer of rationality seeped in and I wondered, "when did my $10 crystal radio project become a $90 digital synchrodyne?" I stammered to the cashier that I couldn't afford it and made an embarassed and hasty exit with the items still on the counter. Sad. It would have been a fun project. Maybe some day I'll make enough money to do some of them.

My next stop was CompUSA. I more than half expected it to not be there anymore. When I first came to Houston, the CompUSA store here was the first one I had been to - they don't have them in the small town I'm from. Murphy's law dictates that since I liked the store, it would naturally have to go out of business soon. The CompUSA company decided this branch isn't bringing in enough profit, and decided to close it up. They've been having a going out of business sale for a month now.

They didn't seem very serious about it last time I was there. Most things were only 10% off. You call that a going out of business sale? Can you even call that a sale? I did get a great deal on a hard drive that time, but I decided to wait and see how much further the prices drop before I buy anything else.

Things have changed quite a bit since the last time. The store looks like a warzone! Now most things are 40% off, half the shelves are stripped, and people aren't so much shopping the store, as looting it. Everything is for sale, not just the products but the shelves too, for goodness sake. One of the store managers asked me, "Why don't you take a basket?" "Oh, good idea," I said. I picked up a shopping basket and behind it was a sign that said, "Why don't you take a basket? Only $4 each." Gee golly, they are serious.

This would be a good time for me to pick up a GPS navigator for my car. I probably burn $200 a year extra gas just from getting lost. The trouble is, I'm dead scared of blowing my money on a crappy GPS system when I could have a better one if I wait. They had some $200-range GPS units for sale at the CompUSA but they were all no-name brands. One didn't turn on at all, and the other could play music but reported "application .exe file not found" when you tried to view the map! This doesn't inspire my confidence in them.

"Even in the future, nothing works!" - Spaceballs.

You know that's the trouble with consumer electronics. Ultimately the manufacturers of these devices are collectively shooting themselves in the foot by sacrificing quality to save manufacturing cost. They've lost the consumer's trust. Even if you're willing to spend the extra money to buy a good product, how do you know you're actually getting something better? Are you really getting a quality piece of equipment, or did a major trademark just slap their logo on a craptastic piece of outsourced junk? Even for an engineer it's hard to tell unless you could look inside the case. Uncertainty is the real reason Americans buy tons of cheap plastic crap and fund a Walmart on every street corner. Given the choice between spending a little money on something cheap and crappy, or risking more money on something that might be better, the same, or worse, people will choose the devil they know and go with cheap over risky every time.

I felt rather bad for the people working at that store. I mean, here are all these shoppers, me included, acting like sharks in a feeding frenzy, yet the staff are being uncharacteristically polite to everyone, and no one is commenting on the larger tragedy that, at the end of this month, a dozen people will be unemployed. I asked one of the younger sales associates about it and he shrugged apologetically and said, "stuff happens". "Are they going to move you guys to another store, or just throw you out on the street?" "Well one guy was going to get reassigned but he quit instead, and there's one other person who got another position." "So, the rest of you...what happens?" "We get a severance package and...that's the end of it."

There were some crazy deals going on, like a TiVo version 2 for $100 and also a laser printer for the same, but I decided to forego the expensive items today and buy more smaller items. I got a USB floppy drive for my laptop for $23, and a book called "The Multi-Boot Configuration Handbook," which looks interesting. I also completed my collection of Swiss-tech keychain tools. I have so many tools on my keychain that I don't keep my keys on it anymore. I need to invent a utility belt that holds keychain widgets! It'll have to be inconspicuous, too, so my girlfriend will not be too embarassed to be seen in public with me.

Of course, what I really want is a Swiss army knife the size of a, well, just look at it! It's huge and it has every blade Wenger makes, but at $1200 it definitely costs more than the sum of it's parts. Kudos to them for having the balls to make something this cool, but they're totally undermining it by calling it "only a collector's item". I would really use this thing. That's got me thinking - how hard is it to hack a Swiss army knife? Why not buy a bunch of smaller Swiss Army knives, break them into pieces, and put together one big one with just the blades you like? Why not make it so the blades are easy to add and remove whenever you want? Then you can have a modular, customizable Swiss Army knife that's as wild and crazy as you want it to be.

I envision setting up an online web store where geeks could buy knife parts to combine together. You could buy blades for $5 each, custom handle-plate designs, and screws and nylon washers to put the knives together. They'd all be interchangeable but every person could have a unique knife, and you could accessorize to no end. A true geek toy.

Too bad the people who make the real Swiss Army knives would sue me out of business.

After CompUSA I went to Barnes & Noble. I've gone longer than usual without buying any books lately. It's not that I don't find books I'm interested in - just the opposite. I can't go to Barnes & Noble without finding a stack of books as tall as I am that I simply must have. I can't afford them all but I can't choose any to remove. So I end up getting none.

But I tell you I have never regretted buying a book. Never. For instance, I spent $143 on a stack of C# books two years ago - that $143 turned into a few thousand I made as a C# programmer right after that.

So I decided it's high time I bit the bullet and actually spent some money on programming books again. (Money has been the thread tying this entry together, I just noticed. It must be on my mind today.)

I had been thinking about getting a book on Ruby for ages now. I decided to get only one and get the rest later. I was drawn to The Ruby Way by Hal Fulton because of its Taoist references (I'm a big fan of the Tao Te Ching, and also The Tao of Programming), but ultimately I settled on the classic Pragmatic Programmer's guide, Programming Ruby, because the writing in it has a light-hearted tone that lifts my spirits. Yes, the old edition is available online, but there is more in the second edition and I still like to read from a real book instead of a computer screen.

Friday, April 6, 2007

Does Code Belong in Essays about Software?

When I wrote Can I Do Without This, it struck me how hard it can be to describe software. In the draft I described a real-world case, detailing how I took the principle I espoused in the essay and applied it to the software I am currently working on. I had to delete those paragraphs. The details distracted from the flow of the writing. I could not make them comprehensible to the reader without going off on a tangent to explain all of the made-up terminology that describes my classes and methods. Software is difficult to describe. I want to speak in specifics, but writing in plain English constrains me to generalities.

Source code exists for the specific purpose of describing programs. Algol (one of the earliest high level languages) was originally invented for the purpose of making it easier for computer scientists to communicate with each other in publications.

However, source code is not English, no matter how many pains you take to make it appear so. Source code is a form of notation, like mathematical notation or musical notes. Good advice for research students is to try to avoid putting math on their slides when they make presentations, lest they lose their audience's attention span. I think the issue is not just math, but that any form of notation is a denser form of communication than what humans are comfortable reading - too dense to put into an essay.

There are other reasons not to mix code with ordinary writing. The formatting that is applied to prose will severely damage the careful indentation structure of a source code example. Conversely, when the source code gets its own formatting, the breaks introduced by switching back and forth rapidly are jarring.

Code and prose don't mix well. This is a real problem if code itself is the subject of your writing. Ultimately, though, we are deluding ourselves if we think that someone is actually reading all the code examples, if we include them. Source code is to be read in the context of pursuing a bug fix or feature change in real source code files. I don't read other people's code examples in literature - why should I be inclined to think that other people will really read mine? When I started this blog, I knew that this issue would surface. I made a decision that I would focus on the articles more than the code examples. It's more readable.

Thursday, April 5, 2007

Good Stuff

Just wanted to share some Good Stuff I've run across in the past day.

Jason pointed me to this video of Steve Jobs addressing Stanford graduates. Frankly I'm surprised they were brave enough to let Steve Jobs talk to students - he speaks his mind, and he's rich enough to tell the truth and not give a damn. This is actually the first time I ever saw him speak. Having seen the video, I think, ah, now I understand why people get so fanatical about him.

You can find a lot of good stories about the early Steve Jobs, and the rest of the original Mac crew on folklore.org. There are over a hundred stories on the site, all very good, detailing the trials and tribulations surrounding the release of the first Macintosh computer. From the site's own description of itself:

"Folklore.org is a web site devoted to collective historical storytelling. It captures and presents sets of related stories that describe interesting events from multiple perspectives, allowing groups of people to recount their shared history in the form of interlinked anecdotes."

Also in the good stuff category, I just popped open a can of Guinness draught. It's delicious! Had quite a head on it too. I'm a big fan of their Extra Stout, but I hadn't tried their draught yet. Draught is similar to Extra Stout, but a lot smoother and maybe more "user friendly".

(For the unenlightened, Guinness is a beer from Ireland that's so strong it has the black color and approximate viscosity of used motor oil. This isn't your wimpy light beer.)

I'm a glass-bottle beer drinker. Not sure how I feel about Guinness in a can, but poured into a drinking glass it tastes good. I like how the side of the can boldly says "beer", you know, just in case you forgot after you got home from the store. There's also a mysterious plastic ball floating in the can, which is, according to the label, the "Guinness Floating Widget". WTF?

I spent part of the day browsing Why's blog about Ruby. Why is the author of Why's Poignant Guide to Ruby, which, along with an interactive online Ruby tutorial, is the reason I became interested in Ruby. Thanks to Why, Ruby must be the first programming language to have a significant book about it written in the style of badly translated Asia instruction manuals. Why is so random, you almost can't judge whether his writing is good or bad; he just kicks things up (or sideways) to a new level (of insanity). But I enjoy it just for the originality. His habit of posting code examples drawn with colored pencils cracks me up every time.

Can I Do Without This?

I have to give credit to Jason Doucette, of xona.com, for reminding me of the topic I wanted to blog today. He said, "To be productive, you truly have to choose what not to do, and avoid it, even though you'll want to do it. Otherwise, it never gets done."

The difference between a good software project and a bad one is that the bad one is in a free-fall of runaway complexity, while a good one merely teeters continuously on the edge of it. There doesn't seem to be a way to build software that doesn't run the continual risk of running amok in it's own sprawling subroutines. It is not the software that has a problem - it's perfectly happy growing wild and wooly. But people can only take so much complexity before their heads explode.

If you just don't care about quality, if you don't have any passion for your work, the statement I quoted about being productive probably doesn't apply to you. You're not going around writing extra code as it is, and that's ok - there's not much I can say that will affect you.

The people I'm trying to reach are those who want to be great programmers, but who perhaps haven't yet found the path. Because you can be very smart and work very hard, only to find that the amount of work required to introduce each change to your beautiful software architecture grows faster than you can keep up with. What happens is that each feature suggests a symmetrical feature as well. If you have a list and a function to add to the list, don't you also need a delete? Not necessarily - if your application doesn't ever delete items from the list, don't write that code. You can write it when and if you do use it - who knows; in ten days you may change your architecture, and not even use that list at all!

You have to be something of a perfectionist to write solid code - you also have to be willing to put up with incompleteness if you want to finish software projects, and that can be a bitter pill to swallow.

I think the reason I had so much trouble with this, is that I learned to program by reading libraries. In the many years I spent learning to program before I had internet in my home, the finest code examples I had were contained in the standard language libraries and headers which came with my compilers. The quality of the code that goes into compiler libraries and language frameworks is usually exceptionally good. What I'm worried about is that smart programmers will fail to grasp the fact that code in a library is targetted for a completely different use-case than code in an application is.

When you look at only libraries and frameworks, you get a skewed idea of which things need to be done and which do not. You risk developing a lop-sided aesthetic sense that values the completeness of a class's API over completeness of the project. When I look at some of my older programs, I realize that what I had were layers upon layers of homemade libraries, building up like a pyramid until at the pinnacle you have one library call which sums up the whole program.

So what's wrong with that? Isn't that the holy grail of software design - to be able to issue one simple command and know that everything else is going to be taken care of?

It's wrong because it took me - f o r e v e r - to finish programs that way. When I look through the code I see dozens of functions which are never called anywhere in the entire program. I put them in, not because I needed them, but just to make the class API complete. Ridiculous!

I'm not alone. I once heard a computer science professor give a group of freshmen the bad advice that, "when you make a class, you should give it as many overloaded constructors as you can, as many as you can think of, in case you need them." Remember, kids, to stock up on constructors; that way you'll be prepared when the global function shortage hits...

The path I alluded to earlier is the way out of the quagmire of slow software development. Imagine the space of all programs as a huge, dark forest. Walking the path means not straying from what you need to write to accomplish your goals. You can write code, even good code, while meandering all over the place, but you will spend much time lost in the forest and may never reach the end. Every time you leave the path to go explore something interesting, you are covering a greater area in the space of all possible programs, making it ever harder to come back from your excursion.

So much for not writing what you do not have to. Yet I am advocating something beyond even that. You must continually re-examine everything you have already written, and eliminate dead code. Do not be wedded to code you have written just because you spent time on it. Instead, value the code only on how much it contributes to the final product.

When I work on software I run variations of the same question through my mind continuously: Can I do without this? Is this a necessary function? If I delete this piece of code, will the rest of the system continue to work?

You can't have bugs in code that is not there.

Sunday, April 1, 2007

I Like that Old Time Rock and Roll

If you want to really understand something, you must go straight to the source. Led Zepplin. The Beatles. Ernest Hemmingway. Shakespeare. The original works in any area may not be the most polished - but they are the ones you will learn the most from. Good ideas have a way of gathering extraneous junk over time - it's as if every original concept is a potential katarami damacy ball, absorbing more cruft with each reincarnation. Eventually it reaches a point that the quality without a name that made the idea good in the first place is completely obscured.

It's easy to see why this happens. Original ideas are rare, and original people are scary. Sometimes they smell bad, too. It's much easier find a person who'll take an original idea and adapt it. There are three ways to adapt an old idea - you can remove part of it, or you can substitute part of it with something else, or you can tack on unnecessary crap. Of these ways, the first two require some understanding of what you are doing. I don't look down on them. Everything is created in the larger context of the culture and technology that spawned it, and I suspect what we call original ideas, are mostly made of other original ideas by simplifying them or substituting parts of another idea.

The third way of co-opting an idea, however, is a form of pollution. It's easy to take a good idea and add something that doesn't change it, because it doesn't break what was already there. Anyone can do it. That's the problem. Look, it's not just a dog, it's a dog with a flower on it's head! It's original! Dog 2.0. The noosphere is littered with junk like this.

The best way to avoid exposure to junk is to go back in time far enough to reach a point before the cruft took over. So when I wanted to understand computer architecture better, I set out to build a homemade system based around one of the oldest 8-bit classics: the 6502 microprocessor. To those of you who may ask why I would want to design my own computer, I refer you to my previous blog entry.

There are all manner of shortcuts that could be taken in such a project. For instance, I could have just used a 6502 emulator on a PC - but I don't want to pretend I have a 6502 computer, I want to have a real 6502 that I can hold in my hands. One shortcut I do think is reasonable is that I am using a powerful modern microcontroller, the Propeller from Parallax, to manage all the I/O and control logic for the circuit. It will allow me to use software to replace a whole handful of support chips. The Propeller is over a hundred times more powerful than the 6502 CPU it will be supporting, but the point is not to make a powerful computer, but to gain a better insight into computer architecture. The Von Neumann architecture, which most computers today are based on, remains remarkably unchanged whether you're looking at a 6502 or a modern Pentium.

(Incidently, the Propeller chip itself is also an example of an original work, the first of its own class.)

My 6502-computer remains a work in progress. I've run NOPs and simple loops on it using its single-cycle facility, but it's temporarily offline while I make some changes. I figured out a way to eliminate even more chips from the circuit, using software on the Propeller to do their jobs, but the computer will not be operational again until I finish writing that firmware.

Even so, I've already uncovered a wealth of fascinating things, which I would never have suspected. Building actual projects provides you with these wonderful Zen moments where your whole plan of action is suddenly brought up short by something unexpected. You find there's a gap in your reasoning and there's nothing in your plans for connecting it. Getting stuck is a wonderful thing because it means you're about to learn something that will change your perspective.

Some of the interesting problems I've overcome so far:

Problem: The hardest part of the whole project is... wiring. If you've never tried to build a microprocessor circuit, you might think that the chips and the signals are what's important. For the most part, those will sort themselves out as you improve your design. But your schematic doesn't give you any hint how to keep hundreds of wires from turning into a horrible rats nest. Bad wiring is the perpetrator of electrical gremlins, and wiring is by far the most time consuming aspect of building a homebrew computer.

Solution: Ribbon cables to keep the mess manageable, and patience.


Problem: The 6502 doesn't always behave the same way every time you reset it. Sometimes it produces junk for six machine cycles before jumping to its reset vector, and sometimes it is seven or eight. This is a problem because my theoretical design depended upon carefully counting the number of machine cycles so that I would know when the 6502 is looking for its reset vector, so that I can substitute another number.

Solution: In my original design, I didn't give the Propeller any connections to the 6502's address lines. I was relying on counting machine cycles to predict what the address should be. I had to change my design, because I needed it to measure actual addresses instead. Plus, you really do need to know the machine addresses for debugging. Guessing doesn't cut the mustard.


Problem: The 6502 I'm using is rated for a 2 MHz clock. I would like to run the 6502 at a slower-than-normal clock speed while I'm debugging it, because certain electrical problems are mitigated by running the circuit more slowly. However, the 6502 uses dynamic RAM for its registers, which have to be refreshed. There is a minimum safe clock speed that will still keep the registers refreshed on time - but what is it?

Solution: It seems no one knows what the real minimum clock speed is. However, everyone agrees that 500 KHz is fast enough. In my own experiments, I found that some operations (like resets and interrupts) would still work at speeds as slow as 10 KHz, but others did not. I've taken to running the processor at 500 KHz normally, and 50 KHz for specific tests.


Problem: The 6502 lacks many "essential" bus control signals. When I first evaluated the chip, I thought, wow, this is really simple. It doesn't have all the confusing extra pin functions that other microprocessors have. Then I went to actually implement the thing and realized there were signals I needed which the 6502 doesn't provide.

Solution: The 6502 has a clock input, as you would expect, but it also has two clock outputs, for no obvious reason. When I first looked at the datasheets, I ignored these because I didn't understand what they did. You can't ignore them. The reason the 6502 appears to be simpler in its bus control pins is that other microprocessors include bus-decoding logic on the chip, but the 6502 makes you use the two clock-phase outputs to synthesize your own bus logic. I first used NAND gates to combine the signals in the way I needed, but my new design will use firmware on the Propeller to decode it on the fly.


Problem: The 6502 single-step feature is very poorly documented, and poses a complex logic design problem. It is also very easy to lock up the 6502 if the single-step pin is asserted at an inconvenient time. (I think they tried to gloss over that in the official docs.)

Solution: I found a schematic of the 6502 single-step circuit that the man himself, Steve Wozniak, used on the Apple II. It was a brilliantly designed state machine using a pair of D-flipflops in a 7474 chip. I'm proud to report that I independently came up with the same idea of using a 7474, and had something already that looked remarkably like Woz's circuit - except for the small detail that mine locked up the 6502, but Woz's actually worked. I analyzed his circuit and realized that the clock-phase outputs (mentioned above) were the piece of the puzzle that I had been missing. Using a flipflop configuration inspired by Woz's, I at last got single-stepping to work, but no sooner had I gotten it working than I realized I could do it in software on the Propeller, without any additional chips.