Thursday, January 22, 2015

QR codes on the BBC Micro, Part 5 of 6: Developing on the Beeb

In which I marvel at how programming has changed in the past 30 years and how it has remained the same, and fret over spurious hardware failures.

After having written a program on the PC to generate QR codes, it was time to do the same thing on the BBC Micro. During a long train journey, I had already written most of the assembly code on paper, so it would be a simple matter of typing it in, and writing the surrounding glue code in BASIC.

I switched on the machine and… nothing happened. Just a slight “pop” from its speaker. A few more tries got me the “boooo” tone normally followed by a cheerful “beep!”. Another few tries, and it went “boooo-beep!” as normal, showed me a prompt and responded to my keystrokes, then froze after a few seconds. Another reboot, and it worked happily for hours, until I turned it off and went to bed.

This was a repeating pattern over the next few days, as I wrote and debugged my program. Every time I wanted to turn the machine on, it took more attempts to get it to work. But every time, it eventually worked. On the last day, it took so long to get the machine working that I just left it on overnight.

But when it worked, it worked well. I found that I loved the predictability of this machine. There is 32 kB of RAM in a single address space, no virtual memory, no processes, no threads. Just your program and the OS – which mostly gets out of the way while your program is running, so you are in full control of the machine.

Compared to modern machine architectures, this is wonderfully simple. There is no distinction between the interpreter, the shell and the editor; the BASIC prompt serves all three purposes just fine. It acts as a REPL, so you can quickly try out oneliners and see if they have the desired effect. If you have broken out of your program with the Escape key or the END statement, all variables remain intact for your inspection, essentially giving you non-resumable breakpoints. The prompt also serves as a shell, so you can save and load programs, list and manage files, and so on.

But the most interesting thing compared to present-day systems is that there is no standalone editor; the prompt is your editor. To make this work, every line in a BASIC program has a number. When you type a line that starts with a number, it gets added to the program in the appropriate place. When you use a line number that already exists, it replaces that line. The LIST command (abbreviated L.) is used to show the current program, or a range of line numbers that you pass to the command.

But what if you don't want to add or replace an entire line, but just make some change to an existing line? This is what the COPY key is for. Using the arrow keys, you can control a secondary “copy source” cursor, which can be positioned anywhere on the screen. When you press COPY, the character under the copy cursor is copied as if you typed it on the keyboard, and both the regular and the copy cursor are moved to the right. This enables you to copy lines from a listing while changing them. It also enables interactive development: you try running a line of code, and when you got it to work, you prefix it with a line number and COPY it into your pogram. Your screen essentially doubles as the equivalent of the clipboard in modern operating systems. But when something scrolls off the top of the screen, it's gone forever, so this mechanism isn't all-powerful.

So far, I've talked about BASIC. But I couldn't write the entire program in BASIC, because it's too slow. It takes about 15 seconds to simply invert all screen pixels, something a machine code program can do in much less than a second – say, 100 times faster. My back-of-the-envelope calculations made it very clear that a 100× slowdown would be unacceptable. But how do we write and edit machine code?

It turns out that BASIC fulfils yet another purpose on this machine: it acts as an assembler. When you write assembly instructions between the characters [ and ], upon interpreting these, BASIC generates the appropriate machine code instructions at the address indicated by the variable P%. The great thing is that it's still “just BASIC”, and you retain the ability to use BASIC expressions to compute values inside the assembly code. This makes for a really powerful system where you get the best of both worlds: the speed of assembly, but the expressive power of BASIC as a kind of preprocessor.

All in all, I was pleasantly surprised by how easy and fast it was to develop directly on the BBC Microcomputer. Of course the development cycle isn't as fast as on a modern system, but it comes surprisingly close. It took me just a few evenings to type in and debug most my hand-written assembly routines. After writing each routine, I wrote a few simple unit tests to make sure it was working, but I threw them away after they passed to save space.

I started by drawing the structural elements of the QR code using BASIC MOVE and DRAW commands, making the parts white where no data would go. Then I turned to assembly to “snake” the data through it. Then some more BASIC to cut out the black pixels of the structural elements, and finally a simple assembly routine to invert all pixels on the screen, because when drawing a black-on-white QR code on the white-on-black screen, I found it easier to think “inverted”. Then some more assembly code to prepare the data codewords by shifting each data byte down by half a byte.

Then, one evening, when I just needed to implement the error correction calculations to complete the program, the computer wouldn't turn on at all anymore. No “boooo” sound, no “pop”, not even the usual slight hiss, no keyboard LEDs, nothing. Retrying did not help. I started eliminating possible causes. First I unplugged the monitor. No dice. Then I unplugged the tape deck. No dice.

Then I unplugged the disk drive. “Pop”, the machine said. A few more tries, and it was running again. Turned it off, plugged the disk drive's power cable (but not its data cable) back in, turned it on, nothing. So it seemed that the power cable was somehow messing with the boot process. Maybe a short circuit in the cable, or in the drive?

I decided to worry about this later. First I wanted to see if I could make a scannable QR code containing some useful data. I put the final pieces of code in place and rendered a QR code containing the byte 255, repeated 2953 times. I did the same on the PC and checked by hand that the pixels looked about right.

A bunch of 0xff bytes in a QR code on the Beeb's screen
Once more, the question was: will it scan?

No comments: