Richardson, TX 75085–1521
Reviewed by Darek Mihocka
Darek Mihocka is a third-year computer-engineering student at the University of Waterloo. His latest ST project was the improved ST Xformer II, and he is currently working on image-processing and character-recognition software. He can frequently be found on DELPHI under the user name DAREKM.
By now, almost everyone reading this has seen Megamax's full-page advertisements in various Atari magazines: "The Fastest C Language available for your ST! Compile and Link the Sieve Benchmark in only five seconds!" Laser C, the long-awaited Megamax C, version 2, is finally available, and it is quite something: An improved GEM shell, a more efficient compiler, a faster linker, a debugger, a real MAKE utility, excellent documentation, no more 32K limitations in the compiler, and more!
Although still very similar to Megamax C, Laser C is a much more complete development package that is easy to use and is among the best I've seen on the ST, although it is not without its share of problems. In this review Laser C version 1.01 is benchmarked and compared with its predecessor, Megamax C, and a few points are compared with Alcyon C and Mark Williams C, although this is in no way a complete product comparison.
Laser C comes on three single-sided disks and with a 600-page manual which is quite extensive. Along with documentation for the compiler, linker and editor, the manual has full documentation for all BIOS, XBIOS, GEMDOS, and GEM calls, and even includes a full chapter on "Line-A" calls. For most functions a sample source code is provided, which is a tremendous benefit to both new programmers and experienced developers who may need to occasionally refresh their memory on how to call certain routines. Sample GEM programs are provided, and even the object code file format is described in the manual.
Laser C shell and editor
To satisfy both those people that prefer to use GEM and those that insist on using a command-line interface, Laser C operates equally as well in both environments. The shell uses custom windows and file selectors, and includes a built-in command-line interface, although Laser C can be used without the shell by using any public-domain or commercial command-line interface.
The Laser C graphics shell can virtually replace the ST's desktop, providing a built-in editor, dynamic disk cache, disk commands and a command-line interpreter. Compiling, linking, and testing of software can all be done from within the shell.
The disk cache is quite an asset. Depending on how it is configured, it can be set to cache both reads and writes, or reads only. It is dynamically allocated by the shell, so as the text buffers grow, the cache reduces its size and flushes out the least recently used files if necessary. Even on a hard disk, it noticeably improves the performance of disk operations, with hit rates usually above 80%.
The caching eliminates the need to set up a RAMdisk for development, as many people do with Megamax C and other compilers. The only problem I experienced with the cache was not being able to turn it off. When the cache gets too full, it tends to slow down, especially when running a program that allocates more memory than is currently available. Time is lost as it reshuffles memory, and the only remedy for now seems to be to periodically flush out the cache.
One nice side effect of the cache is that I was able to compile and run the sample source code files supplied on the Laser C disks while they still had write protection turned on. The cache detects if the floppy is removed and prompts you to reinsert it to flush the cache.
One can install other applications into the shell environment. For example, I prefer to use Tempus as my text editor, so after installing Tempus, to edit a file I simply go up to the menu bar and click on the menu entry "TEMPUS.PRG" instead of "Open." The shell has special menu entries for the compiler, linker, and make utility, and these too can be configured so that, for example, the old Megamax compiler can be used from this shell.
The shell maintains a configuration file so that each time it is loaded, environment variables like search paths, installed applications and editor parameters are also loaded. Similarly, the linker maintains link files for multiple module links.
The file selectors in Laser C are an extension of the standard GEM file selector. They override any other custom file selectors that may be loaded and offer the ability to access any of the possible 16 drives (A: through P:) and have five predefined file masks available. Multiple files can be selected for disk operations, and folders are entered by double clicking, which is similar to the way the GEM desktop windows operate.
The built-in command-line interface is actually another editor window. All text output from the compiler and other utilities is redirected to this window, so that TOS programs can execute without leaving the window-based shell. Since it is an editor window, all text output is captured, allowing one to easily review past compilations. Commands can be executed from this window by placing the cursor on a line of text within this buffer and pressing the Enter key.
The editor, which is an integral part of the shell, can edit up to four text files at once (in addition to the output window), limited in size only by available memory. It is similar in appearance to the older Megamax C editor, although it seems to scroll faster and has some new features. Although I use another editor, I still find it handy to have this editor available to make minor changes to files after, say, a compile error.
One feature I particularly like is the ability of the editor to match opening and closing braces and parentheses. For example, in a complex expression with many levels of parentheses, by double clicking on an opening parenthesis, the editor will locate the matching closing parenthesis.
There is an auto-save option in the editor to automatically save the text buffers at periodic times. The option will also save the text buffers before running a compiled file, so that in the event of a crash, the code is safely saved to disk.
One bug I found in the editor was in the Shift Left and Shift Right commands, which take a selected block of text and indent it (or un-indent it) one tab stop. I found that if the block is too large (about 100 lines or more), the editor will hang up or crash. This bug is supposed to be fixed according to a README file, but obviously they didn't test it enough.
The Laser C compiler is similar to the Megamax C compiler. It still supports in-line assembly code, and offers several improvements. Still being a one pass compiler, it is about the same speed as the Megamax C compiler.
The major change is the elimination of the 32K restrictions found in Megamax C. Both the data and code can now be unlimited in size because PC-relative code is no longer generated. All references to labels and data objects are made using absolute 32-bit addressing modes. This of course increases code size slightly and also increases execution time, but makes Laser C more compatible with the rest of the world and is a necessary price to pay for the ability to write large applications without having to code around 32K limitations.
Up until now, Megamax C users have sometimes had to go to great lengths to convert pieces of Alcyon C and DRI assembler code to compile on Megamax C. With Laser C the code can be taken almost verbatim, so that it is no longer necessary to label code as "Megamax C compatible" as is even done sometimes in ST-Log.
Megamax owners may wonder how much of a speed degradation absolute addressing will cause to existing code. For example, probably one of the most common instructions in C is of the form X = Y, where X and Y are integers. Under Megamax C, this compiles into one instruction, move.w Y(A4), X(A4), which is six bytes long and takes 20 clock cycles to execute. Under Laser C (and most other compilers), the code generated is (and ignore the underscores), move.w _Y.I,__X.I which is 10 bytes long and takes 28 cycles to execute, 40% longer. This is probably a worst case example, since code is not made up only of these instructions. More on this later on.
Table 1 summarizes some benchmark results I obtained using six different setups repeated on two different 1040STs:
- —Alcyon C 1.0 with the new ALN linker
- —Mark Williams C 2.1
- —Megamax C 1.1 on a hard drive
- —Megamax C 1.1 on a 400K RAM disk
- —Laser C 1.01 on a hard disk with an empty disk cache
- —Laser C 1.01 with a full disk cache
Due to the size of the files required for Alcyon, I could not do a benchmark of Alcyon C on a RAMdisk. Based on its very poor results on the hard disk, it probably would not compete with Laser C on a RAMdisk either.
TABLE 1: Benchmark Results
As advertised, Laser C will compile and link the Sieve in five seconds. However, what Megamax fails to mention in their ad is that executable code size and execution times are larger and longer compared to the original compiler. The slower execution speed can be attributed to the absolute code generation. The larger file size is due to what appears to be a larger run-time library, which contains faster, more accurate floating point routines.
Listing 1 is the code for the Sieve benchmark and is provided for your reference.
After modifying the sieve to not use register variables, I got execution times of 4.00, 4.31 and 4.89 seconds for Megamax C, Laser C and Mark Williams C, respectively.
In other tests I tried with much larger source code files, the actual code size stayed roughly the same or increased slightly with Laser C. Although Megamax C usually produces the tightest code, in large programs that require the use of overlays, it generates a lot of extra code in the form of jump tables (to allow it to move between code segments). Larger programs also tend to have more global variables and thus more initialization data. Megamax generates an extra code segment containing an initialization code which executes at run time. Laser C does away with both these extra code problems, which helps to minimize the extra size of its code.
Since Laser C now frees up registers A4 and A5, four address register variables are now available instead of the two in Megamax. Any C function can have a total of eight register variables, four data and four address.
Most Megamax code can be converted over quickly by just removing overlay statements and removing references to A4, A5, and PC from in-line assembler code. Register A6 is still used as the stack frame-pointer and interrupt routines no longer need to go through the hassle of restoring A4.
Laser C automatically optimizes branch statements at compile time, generating a short two-byte branch whenever possible. Megamax C required a separate pass through the object code to do this.
A pleasant surprise was that Laser C compiles switch/case instructions in one of three ways: using jump tables, a binary search or a linear search. The parameters that determine which method is to be used can be adjusted by setting the -s switch when compiling, but simply put, the default configuration works like this: If there are less than 10 case statements for a given switch, and their values are fairly close together, a jump table is generated. Otherwise, if there are more than 12 case statements, a binary search method is used; otherwise, the familiar linear search is used. This means that the programmer doesn't need to worry about the number of case statements he uses and doesn't have to try to code around them by using elaborate if/then/else combinations. Laser C will do it automatically based on the conditions of each switch.
A few minor omissions from Megamax C are now finally included in Laser C. These include support for void and unsigned long types. Much to my disappointment, though, a few bugs in the in-line assembler were carried over, such as the MOVEP and DC.B code generation bugs, although at the time this review was being written, an update with these and most of the other outstanding bugs fixed was available.
Code generation differences
Since the Sieve benchmark is only one of thousands of programs I could have compiled and benchmarked, I decided a better test of the compiler would be to actually look at the code produced by Megamax C and Mark Williams C and compare it to Laser C's code. Comparing to Megamax C code would show where the compiler has been optimized, and comparing to Mark Williams C code would show how different compiler writers implement their code. I used the object files generated by each compiler for the Sieve program and disassembled them.
A problem I encountered on the ST is that all instructions execute in a multiple of four clock cycles. Thus, even though the official Motorola publications on the 68000 may list a certain instruction as taking 10 cycles to execute, it really takes 12. To verity this, I used the program shown in Listing 2 to time individual instructions. The formula works for my monochrome ST; it may need adjusting on other systems, even monochrome ones, since not all STs seem to run at quite the same speed.
While testing the various instructions produced by the three compilers, I found one piece of code that stuck out, and that is in the way the various compilers adjust the stack pointer after a function call.
The fastest and shortest method to increment the stack pointer by values less than or equal to 8 is to use ADDQ.L#nn,A7. When nn is larger than 8 though, the obvious choice is to use ADDA.L# nn, A7 which takes 12 clock cycles, and is the method used by Mark Williams C. Laser C, on the other hand, uses the faster LEA nn(A7), A7 which takes only eight cycles.
Other than that obvious difference, the code generated by the compilers looked very similar, even when it came to register variable usage. All three compilers generate totally different code to access elements of an array, but after timing each of the three code segments, I found they all take 28 cycles each.
I only found one line of Laser C code that disturbed me. Right after one of the floating point operations in the Sieve program, the stack pointer needs to be incremented by 10. Laser C generates an ADDQ.L#8,A7 followed immediately by an ADDQ.L#2,A7. This is just plain brain-dead code! Hopefully these occur few and far between.
The only factor I can see that might cause the poorer speed shown by the Mark Williams C code is that it structures for loops differently, in terms of where the comparisons and branches are placed. The rest of the code was the same.
In general, none of the compilers produce bad code, but none of them stand out as being superior, like Turbo C and Microsoft C 5.1 do in the IBM PC world.
The linker comes with a wide selection of command-line switches, and the linker now produces standard DRI object files. One option I found interesting (although hardly practical to most people) is the ability to relocate the code to an absolute position and link time. Most programs on the ST are relocatable and are bound to a specific address only at run-time. This feature is probably most useful to someone writing code for the cartridge slot, which will then be burned into ROMs.
The linker also has the usual options of producing map files and including a symbol table in the executable file.
The first thing that struck me when using the linker is how fast it is. Compared to the Megamax linker, it is about four times faster, if not more. Programs that used to take a minute to link on a hard drive now take about 10 or 15 seconds. This rivals the speed of Atari's ALN linker. The documentation hints at the fact that the library contains an index which the linker uses at link time. This is similar to the external index files used by ALN.
When linking a desk accessory or an application that makes use of floating point, it is not necessary to do anything extra. No extra libraries need to be linked in, and no weird .L files (that Megamax C uses) are required.
Documentation and utilities
Several UNIX-like utilities are included with Laser C. These include MAKE, LS, CAT, RM, CP and EGREP. The disassembler provided will disassemble any Laser C or DRI-compatible object file. The disassembler will include label names if symbols are present in the file, but only the first bytes of each instruction are in hex.
All of the utilities are documented in the manual, some in great detail, some not. For example, 10 pages are spent talking about the MAKE utility, and examples of simple and complex make files are given. Unlike the bare-bones make function of the Megamax shell, this MAKE utility is full-blown UNIX-type make. One limitation I found is that the Laser C shell only allows for 10 targets to be displayed in the drop-down menu, although the make file can have as many more targets. For more targets, the command line must be used. Anyone familiar with using MAKE on an MS-DOS or UNIX environment will feel right at home using it.
Another 10 pages are devoted to the resource construction program included with Laser C. This I feel, is far too inadequate for anyone not already familiar with using a resource editor. Although the manual gives many examples of GEM routines, I think it fails to explain the importance of resources, and no sample resource files (other than Laser C's resource file) are provided on the disk.
The resource editor is a plain vanilla type. It has most of the basic functions found in all resource editors, and lacks nice features like the ability to produce C-compilable source code of the resource (like Atari's RSC 2.0), or the ability to test resources (like Kuma's K-Resource). However, considering that some other compilers don't even come with a resource editor, it is certainly a welcome part of the package.
The first 100 pages of the manual cover 14 chapters, from the shell and editor, to the linker, to all the utilities. I think this leaves many topics insufficiently covered for the first-time user, although it is more than adequate for the experienced developer.
As I already mentioned, the rest of the documentation is loaded! It contains dozens of sample programs, dealing with everything from creating and displaying a window to using the timer interrupts. It's a good 500 pages of well-written BIOS, GEM and VDI documentation. The Line-A documentation is as detailed as other descriptions I've seen, and of course comes with lots of sample code.
In comparing the Laser C manual with that of Mark Williams C, which is almost identical in content and appearance, I found the Laser C manual to be easier to get around in, since the functions are grouped types, like GEM, VDI, BIOS, etc. In the Mark Williams C manual all functions are mixed in alphabetically, but lots of sample code is also provided.
Bugs and debugging
Laser C comes with a "debugger." I use the quotes because I wasn't impressed with it. For two years I've been using MonST and recently Tempelmon, an excellent public-domain 68000 debugger/monitor program. Although not a symbolic debugger, with Tempelmon it is a snap to track down almost any crashing bug, and it works well with Megamax C.
One problem with Laser C is that it refuses to boot up with Tempelmon resident, and even worse, any programs compiled by Laser C that call the printf() function won't boot either. To make matters worse, the folks at Megamax claim to have developed Laser C using Tempelmon as their debugger.
The problem appears to be an illegal use of the Fdatime() call on Laser C's part, and the Megamax people have been notified of this.
Getting back to Laser C's debugger, it consists of a compiler and linker switches which cause them to generate extra debugging code and a symbol file. The debugger, which is about 30K of code, is linked in with the program being compiled. When it is executed, the debugger is entered. At this point you can set break points, run the program, dump variables, and do all of the usual debugger things at the symbol level.
However, I find the debugger to be more of a kludge than a powerful debugging tool. A couple of dozen well-placed printf() statements in a program can be just as useful. Perhaps I'm spoiled, but having used Tempelmon and the source level debugging in Microsoft's Quick C, I find this debugger to be very limited.
Laser C is available to Megamax C owners as a $20 upgrade—which is a steal! Even if you choose to stick with the old Megamax compiler (if an existing piece of Megamax code is tight and fast, don't mess with it!), the updated documentation will be beneficial and the new shell environment is simply fantastic. And you'll still get the same great phone support and update policy as with Megamax C.
For small programs, it is much easier and faster to develop under the Laser C environment than the Megamax environment. If code size or speed is really critical, the finished product can always be compiled with Megamax, since Laser C upgraders don't lose the right to use their old compiler. A nice feature would be for Laser C to have a compiler switch to compile using the old PC relative code, but such is not the case, and so both compilers should be kept handy.
As before, Megamax Inc. doesn't require you to pay them a licensing fee or even put up any sort of copyright notice in your software for the use of their run-time library.
Laser C is not perfect. It has the few annoying bugs and it still produces the odd "brain-dead" code here and there, although overall it appears to produce as good or better code than Mark Williams C or Alcyon C. At the time I was writing this, I had not seen Mark Williams C 3.0, and I've been told to stay away from the latest version of Alcyon due to bugs. Nor did I compare Laser C to other compilers (Aztec C and Turbo C are rumored to be coming, and nobody really uses Hippo C or GST C, do they?). If and when those compilers make their appearance on the ST market, it will be interesting to test them.
However, Laser C is not just a compiler. It is an entire C-language development package. As such, compared to what is currently available, I feel it is without equal in the ST world. For now, I don't hesitate to recommend the Laser C package to anyone interested in C programming on the ST. Time will tell whether Megamax will make frequent enough updates to their product to maintain par with other compilers, especially with the juicy features Mark Williams C 3.0 is supposed to have.