MJK C compiler disks
C Programming Reference
Books in PDF
CGFX7 Graphics Library User's Guide
K&R The C Programming Language
Mike Knudsen's Coco 3 / OS-9 system
used for compiling UltiMusE 3
In December of 2011, I was discussing the sources of Ultimuse 3 via email with the program’s author, Michael J. Knudsen, as I was trying to write a Multi Format Music Player for the Color Computer in OS-9. Mike was more than willing to share his old sources and file formats to his flagship program. He had referred me to Boisy Pitre to whom he had sent a copy of all the sources to Ultimuse. I had gotten that package from Boisy but the code I really needed was the source to “UBox3”, the jukebox player for Ultimuse format files, as I just needed a player and not the full blown editor. These files were not in the archive I had received form Boisy. Mike informed me that he still had his old Coco system and he would crank it up and see if he could locate the sources I needed. In doing so, he asked if I knew anyone that would be interested in his old Coco system. I immediately jumped at the offer. After working out all the details, he informed me I would be receiving his monster Coco system, complete with the hard drives with all his sources and notes for Ultimuse 3. Ultimuse 3 was the very MIDI sequencer I had used for ten years to compose and edit my music until I finally moved on from the Coco to bigger machines. To have the original machine it was written on and the sources to the program was like a guitarist getting a hold of Jimi Hendrix’s guitar. I was ecstatic to say the least.
I finally received the system on December 28th 2011. It was like having Christmas day twice in one week. 3 huge boxes of goodies for me to open. The system consisted of a color Computer 3 with a 1 meg memory expansion and an Eagle AT Keyboard interface. There were 3 floppy drives; a 5 ¼” 360k 40trk DSDD, a 5 ¼” 720k 80trk DSHD, and a 3 ½” 720k 80trk DSDD drives. There were two floppy controllers; a J&M No halt controller and a Radio Shack FD-502 controller. The hard drive was a Burke & Burke system with the B&B controller and two Seagate ST-225, 20 meg drives in a monster drive case. There was also an old “Grey Goose” Multi Pak Interface (upgraded for Coco 3), a Glenside Midi Pak, Deluxe 2 Button mouse, and several other items plus several boxes of floppy disks. The real prize was a Tandy CM-8 RGB monitor. What a system! (pictures on my website)
There was originally some problems getting the system going as Mike had forgotten to include his custom OS-9 Level 2 boot disk for his hard drives in the package and I couldn’t boot the system to get to those hard drives! And Mike had gone on vacation to Mexico for several months! The floppy drives were also in need of a good cleaning and would not read disks properly until I had thoroughly cleaned the heads and moving parts. After a lot of trial and error and reading through the B&B XT HD manuals several times, I finally created a boot disk and got OS-9 booted. But... alas... the hard drives would not spin up. After investigation I found that during shipping, a screw had come loose and had been rolling around in the hard drive case. It had lodged itself into the power supply and when I cranked up the system, the power supply had fried. I then found an old power supply that would spin the drives and found that drive 0 would not complete the spin-up test at all and would fail. Drive 1 would spin up and read, but would only do so for about fifteen minutes before getting too hot and shutting down. Drive 1 was apparently being used as a complete backup to drive 0 and according to the notes I found on the drive, it had been backed up just a few weeks before Mike had told me he had quit using the Coco and parked it. I proceeded to copy the files from the hard drive during the 15 minutes it would run and save them to virtual hard disks using DriveWire. With the drive acting as such, this process took about two weeks to get all the files that were intact. I did find a few files that were errored or corrupt.
After finally getting the surviving files to VHDs, I started sorting through the files to find the sources I was needing, the UBox3 code. When I finally found them and loaded the first file into a text editor, I thought I was reading Japanese! It was all written in C compiler code. I had never programmed in C but I had done some work in RSDOS EDTASM as well as in BASIC09 and OS-9 Assembler. C was something from another world.
Bound and determined to use this code for my player, I downloaded all the manuals and documentation for the Color Computer - OS-9 C compiler I could find on the internet. I felt like it was the 80s again and I was learning assembly language. As I started comparing Mike’s UBox3 code to examples I found of other software written in C and the commands and syntax I saw in the manuals, I knew something was different. Not only was Mike’s coding style more “in depth” than the others I was seeing, but his makefile for compiling was unlike anything I could find examples of. Mike had told me in our last conversation that he had a special system for compiling these files but he hadn’t given any details as to what and where it was. The only clue I had was a note he had sent to Boisy Pitre when Mike had submitted the Ultimuse sources to add to the OS-9 repository (which never made it there I notice) and the note mentioned several “extra” files needed to compile Ultimuse3. These were “c.comp”, “rcr”, and “CnoY”. I had no clue as to what these files were but searched my copy of his HD and found c.comp and CnoY but both files were corrupt. After asking on the Coco new list, I did locate a copy of both on Gene Heskete’s website but Gene could not remember why they were there other than they were part of the C compiler. The rcr file was no where to be found. In searching Mike CMDS directory and also his startup file for OS-9, I noticed he loaded and executed a file called “CLoad” during startup. Out of curiosity I located the file and found it was just a text script that loaded his compiler system on startup. A real dedicated programmer! I now had a list of all the modules in his C compiler.
The first thing I noticed in the list was a program called RCm2. I searched the CMDS and found it. After using dEd to take a look at it ,I found that the internal name was “rcr”. The very file I was missing. He renamed it to avoid clashes with an older version that apparently had been deleted after finding the new one ran as intended. It had just never been renamed.
At this point, I apologize for the long story but I felt I had to document how I came about this compiler system as it was an adventure in itself. Now to explain what this compiler is and how it works. Not being a seasoned C programmer, you may find some of my explanations crude and maybe even in the wrong terminology, but I will do the best I can as this system has to be one of the best C compiler system ever assembled for the Color Computer 3 and OS-9 Level 2. When set up right, it makes the compiling process effortless.
So without further adventures... On with the show!
B.P.
I will start this tutorial with the list of modules from the “cload” script. These are the essential files of the compiler:
Note: This compiler system should work with any version of OS-9 from stock Tandy/Microware to NitrOS-9. Mike was running a slightly patched stock OS-9 when he put together this compiler system. BP.
Also, I use this C compiler system with VCC ver 143 with Becker Port support configured with DriveWire 4 running NitrOS-9 ver 2.3.9. I have the VCC Coco 3 emulator running with a highly overclocked CPU speed and overclocked disk access. This enhances compile speed by about 2000% !!
A complete fresh compile of my DW4Man program suite with 52 source files on VCC at "normal" clock speeds takes about 16 minutes to compile. The real Coco would probably take about a couples of minutes longer :-(
The same 52 files compiled with VCC overclocked to 75mhz takes about 20 seconds!!!
After compiling on VCC, with a couple of mouse clicks, the vhd is transferred to DriveWire 4 on my real Coco 3 and up and running in less than a minute total !!!
These are the main files used in the compiler. The list is a copy of the “cload” script. The "cload" script first loads and runs "NMLoad" then NMLoad proceeds to load the remaining modules, leaving them in memory after it's done while NMLoad itself exits from memory''.
I will now try to explain the use of these files and some others that are also used in the compilation process or are just “good” utilities for C compiling. All descriptions end with a pathlist to where the files should be located.
This C compiler system is the same system Michael Knudsen used for compiling the massive UltiMusE 3 Midi Composer program. Mike wrote several of his own utilities and utilized the latest updates and rewrites of any C compiler module he could find on Delphi, Compusrve ot the OS-9 User’s Group Library. I have added a few enhancements to make it even faster and more efficiant as Mike would have if he had continued to work with the Tandy Color Computer and OS-9. He eventually moved on to the ill-fated MM-1 and then to PCs running Linux. He has ported his Ultimuse 3 program to both platforms and still updates Ultimuse today on the Linux operating system. I was given permission by Mike Knudsen himself to use these sources and utilities in any way I wanted as long as I continue to credit him as the originator.
There will be three virtual disk images in OS-9 format (80 trk DDDS) included in this tutorial package. These images can be used on any of the Color Computer 3 emulators or on a real Coco3, either must be running OS-9 Level 2 or NitrOS-9 Level 2. If you are using DriveWire, then the DriveWire drivers must be installed on your sytem boot disk. The only other stipulation to this system is that you MUST have a ramdisk in your bootfile with an “/r0” descriptor. The C compiler system could be recompiled to use another default temp drive but using the ramdisk just makes sense. It’s much faster than a floppy or hard drive and some larger source packages will definately benifit from the extra speed.
I have included a ramdisk package with this tutorial and I would advise anyone who regularly uses a ramdisk to switch over to this one as it’s the fastest, most reliable, and most conveniant ramdisk I’ve ever used. Kevin Darling eat your heart out! This one “just works” (TM). It waswritten and rigorously tested by Gene Heskett and I will never use another one. More on this later.
As I said, you must have a ramdisk installed. All directories on the system disk must be copied “as is” to your working system disk. To do this, you can use the "arc" program on the CMDS disk. just mount and type "/xx/cmds/arc -amu /xx /dd" and all files will be copied with their directories intact. Arc will then be in your cmds dir so you can use it directly on the other disks. Almost all commands and functions in this system default to“/dd/cmds” for the compiler modules, “/r0” for the temp files, and “./RS” in your working source directory for the unlinked reloacatable object files (“xxxx.r”). I have tried to include all the headers and libraries that have been updated or rewritten for a completely updated C compiling system.
Along with this C compiler tutorial, I have included virtual disk images containing all the C compiler modules, any documantation I could find for any given module/utility as well as a another disk image containing a copy of Mike Knudsen’s “UBox3” source files. UBox3 is perfect to use as a tutorial as it is a multiple file source combining assembler sources along with C sources. The “makefile” for these sources is a good example of compiling large multi-file sources and I think this is the main reason I particularly chose this program to use as an example. With the UBox3 sources you will see how simple it is to compile these types of packages in one fell swoop. No, I will not be including a tutorial on Mike’s C programming style. You will have the sources... have a go at it yourself. Mike is one of those guys that if a piece of 10 lines of code would compile to be 1 cycle faster in the final object than the simple single word command provided by Microware that did the same function, he would opt for the more complex method to gain that cycle. He knew the K&R C manual inside out and could quote from the book.
The goal of this tutorial is to explain the process of using multiple source files in multiple formats to compile large program files. The UBox3 sources used are not by any means the largest collection of C sources I’ve seen or compiled, but it’s large enough to represent this unique compiling process and small enough that I could get it all on a floppy disk image. Any documentation I can find for any program included with this tutorial will be stored in the “DOCS” directory on the included disk image.
We will start the tutorial with the makefile. This is the heart of the compiling process. In the makefile, you can define each and every operation the compiler is to do to your sources and what to do with them when it’s done as well as what to do with the program(s) it creates. We will be using Tim Koonce’s “Make” which was a makeover of Microware’s make module with a few extended features and some bug fixes on the original. The whole process is not that much different from the normal method with the exception of the long command lines and multiple filenames needed to be typed in when using Microwares C compiler. The “RCm2” modules used by “make”, streamlines the process utilizing the ramdisk for faster compiles on a real Coco and lightning fast compiles on an overclocked emulator like Vcc. Personally, I use Vcc exclusively for all my compiling due to the speed in which it does the job. In just a few seconds, I can do what it would take the real Coco to do in 15 minutes to and hour. The original Ultimuse 3 sources consist of over 125 source files and headers that compile into about 13 seperate files and takes several hours to compile on a Coco 3 running NitrOS-9 from a hard drive! I can compile it on Vcc (max overclocked) in less than a minute! And by using just one command... Make.
The makefile for UBox3 looks very intimidating at first glance. I’ve looked at many sources in the past year, large and small and have never seen anything like this done on the Coco. Mike specifies each and every thing that builds into each source therefore controlling the memory he’s using in the final file. All direct page variables have their own source file as do the global variables. Then each individual source file has it’s own local variables that when compiled, will be used in the stack. The way he lays out his makefile reflects the thought that went into the organization that went into the sources. So with all that said, here is a listing of the makefile to UBox3. It is an unedited copy directly from Mike’s HD image.
***********************************************************
* To make Jukebox UltiBox file "UBox3"
* Upgraded for Tim Koonce Make 90/3/17
* Stackchecking turned off for production 89/10/15
*
* General rules. .c.r specifies how to compile .c files into .r files.
.c.r:;rcr $(RCRFLAGS) -d$(RDIR) $*
.a.r:;$(RMA) $(RFLAGS) $< -o=$(RDIR/)$@
EDIT=4
ODIR= # was /h0/cmds for Tandy Make bug
RDIR=RS
RCRFLAGS = -s -y
*
JFILES=jvirt.r jdp.r jglob.r juke.r jsubs.r jinit.r jio.r jmenu.r\
jplay.r jplaysubs.r
CFILES=juke.r jsubs.r jmenu.r
*
UBox3: $(JFILES) serial.r getclock.r
UBox3Link
jmenu.r: titles.h version.h
jglob.r: size.h titles.h
jinit.r: size.h version.h
jio.r: version.h buffpage.h
jplaysubs.r: keys.h
*
* Always put groups of dependencies after the individuals
* Next cmd lines also apply to .c dependency, yippee!
$(JFILES): jmuse.h
$(CFILES): jcolors.h
serial.r: serial.a
*
* eof JukeMake
***********************************************************
The documentation to TK’s Make is in the DOCS folder on the disk image. These docs are really sparse in explaining the make process. Even the OS-9 C Compiling manual doesn’t explain this process to it’s fullest. With the use of “macros”, you can streamline most any compiling operation. The macros are represented by a “$” followed by a command in all uppercase letters and in parentheses. There is some explanation of these macros in the documentation, but not much so I’ve had to figure a lot of it out by trial and error... a lot of errors!
We will now break down the makefile into it’s various components and see what they do.
The docs to make can explain a lot of things, but I will attempt to explaing some of the simpler aspects here in a breakdown of the Ubox3 makfile
First in the file is the :
* General rules. .c.r specifies how to compile .c files
.c.r:;rcr $(RCRFLAGS) -d$(RDIR) $*
.a.r:;$(RMA) $(RFLAGS) $< -o=$(RDIR/)$@
As it says in the 1st line, you are setting the rules as to what program will be used to “make” the file, and where it will be put. These command will overide the setting in the “make.default” coniguration file found in the /DD/SYS folder. The capital letters indicate a Macro, of which is (for the most part) defined in the “make.defaut” file in the /dd/sys dir.
All that is being said in line 2 is that “rcr” will be used to compile “xxxx.c” files into “xxxx.r.” files and that any “flags” set for rcr are to be used. These are set with a command further down in the makefile.
The 3rd line states that RMA will be used to assemble the “.a” files into “.r” (by rcr), also, it states the default directory these files will use. This is also set later.
For the most part, I leave this alone, as it is more or less hard coded into the rcr sources as well and you want the makefile to reflect the settings in rcr.
The next set of lines deifne our compiling parameters:
EDIT=4
This sets the "Edition" number in the final compiled module.
ODIR= # was /h0/cmds for Tandy Make bug
The ODIR defines the default dir that the final executable object code is to be put, but we actually define that later in the link file, so that’s why this is left blank. I assume it was defined blank to overide the defaults so there would be no conflict with the linker.
RDIR=RS
RDIR is the macro definition for what dir we are going to put our “.r” files. I like Mike’s idea of an RS dir in our work directory so I leave it as is. Just make sure your source dir has an RS dir within it. If not it will error out on compile. I have downloaded a lot of sources the apparently had been compiled before zipping and every “xxxx.c” file had a matching “xxxx.r” file, making the directory hard to navigate. The Microware system stores these files in the current working directory as a default. Using the RS directory moves all these files out of the work directory and provides a convenient place for “touch” to date them. It also cleans up your work directory, leaving only your sources.
RCRFLAGS = -s -y -c
Then the RCRFLAGS defines what parameters we are going to pass to rcr and eventually to each of the compiler modules. To get the rcr options just type rcr -? and you will see all the options for rcr. The “-s” signifies that we want stack checking turned off. You may want this omitted until your code is fully debugged as it’s easy to have a “stack runaway”. The “-y” states the we want to use the CnoY utility. This is optional and occassionally I find a program source that will not compile with this option set. If you start getting “Bad Cmd” errors in the assembler phase, then omit this option. “-c” states that we don’t want to clean up the temp files that are created while compiling. These files are in the “/r0” on the ramdisk. Rcr is hardcoded to use the ramdisk but could easily be changed in the sources to any directory you want and recompiled.
The source code to rcr is in the CSOURCES/TOOLS dir if you want to look at the inner workings of rcr. It’s an intersting tutorial on coding to use external modules from within a C program.
Next we define how our files are compiled:
JFILES=jvirt.r jdp.r jglob.r juke.r jsubs.r jinit.r jio.r\
jmenu.r jplay.r jplaysubs.r
CFILES=juke.r jsubs.r jmenu.r
These lines are basically defining a Macro that says any operation on JFILES is done to every file on the list. Then he defines a second set called CFILES. The \ used in the list indicates that this line continues on the next line. Notice the 2nd group is actually files that were in the first group. These groups are created so they can define the dependacies that they will be using together. You will see more on this towards the end of this tutorial.
The next set will be
UBox3: $(JFILES) serial.r getclock.r
UBox3Link
This states UBox3 as our end-file name for the project. With this you can create multiple compiles of seperate programs from within one makefile. Mike’s actually uses this in Ultimuse3 makefile as he compiles all the subroutines and the main file in one process.
It simply states that UBox3 will use JFILES to be compiled and that the following files will be add to the compilation. The added files are actually RMA assembler files and not needed by the first phase, but will be assembled with RMA. Then the 2nd line states that the external script UBox3Link will be run to link the resulting “.r” files when the compiler is done. (more on this script in the Link tutorial). The Lines from UBox3Link could also be put in the makefile to avoid running a 2nd script. I think Mike seperated his due to the sheer size of UltiMuse and split it into external linker files to make editing easier.
Next is a list of files with no “common” dependacies.
jmenu.r: titles.h version.h
jglob.r: size.h titles.h
jinit.r: size.h version.h
jio.r: version.h buffpage.h
jplaysubs.r: keys.h
These files are the only ones in the sources that use these particular dependacies or combination of dependacies, so they have to be listed individually.
Last in line is the group dependacies:
$(JFILES): jmuse.h
$(CFILES): jcolors.h
serial.r: serial.a
All the files list in the JFILES use jmuse.h. All the files in CFILES use jcolors.h. This keeps us from having to list all these files individually, simplifying the process. I’m not sure why the serial.r lists the serial.a as a dependacy, as the getclock.r does not list getclock.a as a dependant. I have done compiles with this commented out and it seemed not to matter, so I’m not really sure why this is done.
I don’t know if you grasped my simple explination of the process, but you may understand the docs better. I usually use this file as a “templet” and change all the files to my files and use my own naming conventions and it usually works pretty good.
Using the Linker File
Now for the final step in the compilation process. The link file.
Again, I will use the link script for UBox3 as an example.
* echo UBox3Link == build Virtual Memory Ulti-Jukebox
chd RS
t
RLINK -o=UBox3 -M=7 /dd/lib/cstart.r jdp.r jglob.r juke.r jvirt.r jplay.r jplaysubs.r serial.r jinit.r jio.r jsubs.r jmenu.r getclock.r -l=/dd/lib/klib.l
*(all 1 line from RLINK to klib.l)
-t
This is the simplest part of the process, “-o=” is the name and path of the final executable object, and “-l=” are the paths and names of the C libraries used.
Notice: this is where you add the cstart file. It must be the first file in the list as the files are compiled and merged in the order they appear here.
In between are the files being linked, in the order in which you want them linked. Up to this point, order has not mattered. But here, you must order them as you want them in the final object code.
When this script runs, the the final executable obect is linked into one file and place in the dir you described above. Using no path as above should default to “/dd/cmds/”, but I haven’t tested this.
This ends the complete C compile process. Getting the makefile right is probably the hardest part to understand (for me) but once you undestand what is being done, it’s pretty painless. Make also has a few options of it’s own that can be called on the command line when you provoke make. To see these optione type
make -?
The real change to this compiler system is the use of RCm2 (rcr), C.comp & CnoY. These 3 files along with the new “make” will produce faster, more efficiant, and much more stable code than any compiler I’ve tried. Any one who has used my “Sound Chaser” music player for OS-9 or my “DW4Man” for NitrOS-9 and DriveWire has seen the results of this compiler system. I’ve used it exclusively for these programs.
As I think of things I've missed in this tutorial, I will add them as soon as I get a chance. For now, enjoy the MJK C Compiler system. I know I have :-)