Part 1 – The Ascent from Assembler to C
It was late in 2003 when I received my first AmigaOne-XE. At that time, like many others, I had to be content to use Linux, and I waited impatiently for the day when I could run AmigaOS on my new machine. In the meantime I built the Boing Ball “case” for it. [The XE board failed in 2014 after eleven years of faithful service. These days the Boing Case is occupied by the AmigaOne X5000]
Early in 2004 I was invited to become a beta tester and had the good fortune to be able to run the 68K version of AmigaOS 4 on my A4000. At that stage most of the old AmigaOS software had been modified (where necessary) to compile with GCC, and the developers were mainly using cross-compilers running under Linux or Windows. Many of the system components, originally written in 68K assembler, had already been rewritten in C or translated to C. Only a couple of months later, the first PPC versions of the system components were released to beta testers and 68K versions were dropped, one by one. Only a handful of third-party components remained in 68K, those for which we had binary licenses only (e.g. ARexx).
During a discussion on the beta tester mailing list one day, one of the developers mentioned that only the console device remained to be translated/rewritten in C. Foolishly I waved my hand in the air and said something like “I’d like to have a go at that!”. Well, I had been an assembly-language programmer for probably thirty years and a C programmer for probably twenty, so I thought it might be fun.
You can imagine my excitement when, some weeks later, an archive arrived in my inbox. It was the assembler sources for the console device, all 26 source files and about half a dozen header files. Where was I going to start? I couldn’t just translate the whole thing in one pass, then sit down and attempt to debug it. I had to be able to switch back and forth between assembler originals and C translations, or I would never be able to even make it run, let alone debug it.
I decided to use SAS/C, the 68K compiler/assembler package that I had been using for years. Like many other packages, it allows you to mix C and assembler modules freely in the build. I could translate each assembler source file in turn, and with some stubs, call the assembler functions from C or the C functions from assembler. That way I would be able to switch individual modules back and forth between C and assembler at any time. I started by compiling the source on my trusty old A4000, since the A1-XE was by now the beta test machine and the A4000 was the stable development platform. Later, the native AmigaOS 4 version of GCC was released and I was able to compile and build on the A1-XE (it was a bit faster than the A4000, even with its 68060/50 processor!).
Well, the translating job took about nine months. I took each assembler source file and commented out the assembler statements, writing in the C version underneath. Of course, this approach made each source file huge, but it would prove to be a boon later when I was debugging, since I could see the original side by side with my translation. During that time I had to break up some of the assembler source files into smaller modules, just to keep them a reasonable size. I finished up with some 30 C source files.
Here is an extract of part of a translation:
// lea cd_RastPort(a6),a1
// move.b cu_Mask(a2),rp_Mask(a1)
// moveq #0,d0
// move.b d6,d0
// LINKGFX SetDrMd
You can see that the original five lines of assembler have become two lines of C.
The makefile was huge, with half of it commented out at any one time. The SAS/C suite produced 68K code, but from a mixture of C and assembler sources. At first it was all compiled on the A4000, but later I swung everything over to the A1-XE and made that my new development platform.
As the development progressed, there were fewer assembler sources and more C sources, until the first pure-C version was released to the beta testers in May 2005. That version was still compiled by SAS/C and distributed as a 68K binary. There were several more months of debugging and testing, until the pure C sources were compiled into native PPC for the first time in August 2005. At about the same time, the C sources were stripped of the original assembler code and we had a working console device, written in C and compiled in pure PPC. We tested it to destruction and cleared the bugs before it was finally released to the world. Most of the bugs were inconsistencies with the old 68K version, caused by mis-translation or errors in understanding. It had taken a year to translate and debug, but it was a great satisfaction.
The original 68K assembler version of the console occupied 16,212 bytes. Compare that with the last 68K C version (V50.26) which was 42,564 bytes! It just shows how squashed the assembler version was (but that C version did have some debug code as well).
The translated console had several drawbacks. Because the original had been written in assembler, it was very difficult to read and maintain and there were a number of known “features” that were just too hard to fix. Also, the assembler version had been written to minimise code size, rather than to optimise speed or code legibility. There were many tricks employed within the assembler code to save a few bytes of space in the Kickstart ROM. For instance, it was common to arrange several byte-sized variables adjacently in the data area so that four variables could be picked up at once with a long word fetch. Not recognising these tricks was the cause of many a bug in the early days! Also a lot of the ANSI code had been not implemented in order to save space.
Not the least of the drawbacks was that the memory allocated for the display was fixed when the window was opened, and lines of text that scrolled off the top or bottom of the display were scrubbed clean and re-introduced at the other end. It was just not possible to save the scrolled lines to keep the display history. To add a scroll bar and history would need a big rethink of the architecture.
Next time: the Great Console Rewrite.