• Please review our updated Terms and Rules here

Which C compiler do you prefer for CP/M?

Quite a while ago, I decided to compare a variety of the more popular CP/M compilers (C, BASIC, Pascal, FORTRAN, etc. .... even PL/I). It was my opinion that many of them were painful to try to use back in the day with the typical 4 MHz, floppy-based Z-80 systems. I have some homebrew Z80 SBCs that run at around 20 MHz with compact flash "disk" using native Zilog VLSI (and CP/M 2.2). Most of these compilers were quite easy, and comfortable, to use on that hardware. I used the ASCII art application that draws a Mandlebrot figure using ASCII characters on the system console. It is loop intensive and requires floating point. I found that HiTech C gave the fastest execution times. My comparison included a few versions of C -- IIRC HiTech, Aztec, and BDS. None of the others even came close. But, I also seem to remember that HiTech was not the best in terms of the size of the executable? Can't remember all the details now. I had to jigger the code around (quite a bit in some cases) to get it to compile and run with some compilers and languages. I'm not particularly facile in some of these languages, so perhaps that had a negative effect on the comparison? As I remember FORTRAN, and Pascal were the most difficult adaptations? It is my opinion that Pascal is a "begin-end" nightmare!!!

Roger
 
It is also my own experience that binaries produced by Hi-tech C are bloated.
 
Hi,
There's also Mark Ogden's Linux version of the HiTech C compiler available, and Tony Nicholson, another HiTech C giant, is providing support too.
The toolchain, which runs natively on Linux, allows significantly larger source codes to be compiled, similar to Ladislau's modification, ultimately limited only by the size of the executable file.
Martin
 
In fact, the Mark Ogden reconstructed source files of HiTech suite were the starting point for my version of the compiler which runs on 128/512KB RAM Z80 CP/M systems. I took these files and it took me two years to modify them in order to allow compiling/assembling larger files, compared with the original HiTech v3.09 Z80 version. Thanks again Mark!

Just an important note: my enhanced HiTech C compiler does not compete with Tony Nicholson's software.
In fact, these are the two complementary components that make up the HiTech execution environment : my part comes with the C compiler executables, Tony comes with an improved LIBC & LIBF libraries.

thanks,
Ladislau
 
And now for something completely different...
Does it make sense to consider using C modules in the BIOS, e.g. for blocking/deblocking (CP/M 2.2) or RAM disks?
Although - IIRC - I found this quite easy to implement in assembler in the 1980s.
Martin
 
IMHO, no. I would never use C or any HLL to implement a BIOS. But that's just me. Way too much bloat for my taste.

One thing I have done is implement prospective algorithms in C, and once tested I do a one-time conversion to assembler.
 
IMHO, no. I would never use C or any HLL to implement a BIOS. But that's just me.
It may depend a lot on the compiler, and the target architecture. Some archs are better targets for C than others.

I do a lot of work with the Motorola 68000, and I use GCC to compile C for it, and I wouldnt have it any other way. A lot of the time, when I examine the disassembly, it does about as good a job as I might do by hand anyway. What ever small performance hit there may be isnt enough to make me want to ditch C outright.

I am much more productive writing C, but when I really want to do something my way I can use inline assembly or write a routine in assembly that I call from C. Best of both worlds.

But the 68000 is a much better target for C than, say, the Z80. Ive not tried to compile C for the Z80, but I suspect if I tried I'd be less than impressed with the results too.
 
In my opinion, if the C compiler has an option to show the assembler source code produced as the result of the compilation, it would be nice to study that code and to improve-it, as a first step (HiTech C has such an option). But, I would newer use directly the result of C code compiled by any C compiler into BIOS.
Ladislau
 
Correct: option -s produces *.as output

Code:
A>c309-19 -h
Hi-Tech Z80 C Compiler (CP/M-80) V3.09-19
Copyright (C) 1984-87 HI-TECH SOFTWARE
Updated from https://github.com/agn453/HI-TECH-Z80-C
HI-TECH Z80 CP/M C compiler options:

-A      Generate a self-relocating .COM program.
-C      Generate object code only; don't link.
-CR     Produce a cross-reference listing e.g. -CRfile.crf
-D      Define a symbol, e.g. -DDEBUG=1
-E      Specify executable output filename, e.g. -Efile.com
-Ffile  Generate a symbol file for debug.com or overlay build (default L.SYM)
-H      Output help (the OPTIONS file) and exit.
-I      Specify an include directory, e.g. -I1:B:
-L      Scan a library, e.g. -LF scans the floating point library.
-M      Generate a map file, e.g. -Mfile.map
-N      Use the NRTCPM.OBJ start-up with minimal _getargs().
-O      Invoke the peephole optimizer (reduced code-size)
-OF     Invoke the optimizer for speed (Fast)
-S      Generate assembler code in a .AS file; don't assemble or link.
-U      Undefine a predefined symbol, e.g. -UDEBUG
-V      Be verbose during compilation.
-W      Set warning level, e.g. -w5 or -w-2
-X      Suppress local symbols in symbol tables.
-Y Generate an overlay output file (.OVR file-type)

This tiny program

C:
#include  <stdio.h>

int main() {
        printf( "Hello, world!\n" );
        return 0;
}

produces a lot of as output

Code:
...
;hello.c: 3: int main() {
psect   text
global  _main
_main:
global  ncsv, cret, indir
call    ncsv
defw    f30
;hello.c: 4:    printf( "Hello, world!\n" );
global  _printf
ld      hl,19f
push    hl
call    _printf
ld      hl,2
add     hl,sp
ld      sp,hl
;hello.c: 5:    return 0;
ld      hl,0
jp      l2
;hello.c: 6: }
l2:
jp      cret
f30     equ     0
psect   data
19:
defb    72,101,108,108,111,44,32,119,111,114,108,100,33,10,0

and finally a big com file (even with option -n to avoid the argument globbing overhead)

Code:
-rw-r--r-- 1 horo horo 3602 12. Jun 09:42 hello.as
-rw-r--r-- 1 horo horo   77  9. Jun 17:41 hello.c
-rw-r--r-- 1 horo horo 8441 12. Jun 09:50 hello.com

But it could be a good starting point for simple algorithms w/o many calls to libc.

Martin
 
Last edited:
Martin,

try to compile-it also with the "optimization" flag:

>c -v -c -o -s hello.c

You will notice some small improvement in the assembler file being built, compared with the previous file, build when -o is omitted...

Those improvements will be however significant when the C program is more complicated...

thanks,
Ladislau
 
I do a lot of work with the Motorola 68000, and I use GCC to compile C for it, and I wouldnt have it any other way. A lot of the time, when I examine the disassembly, it does about as good a job as I might do by hand anyway. What ever small performance hit there may be isnt enough to make me want to ditch C outright.
Agree 100%, Tom. I use the GCC toolchain to produce code for my homebrew 68Ks. The code that comes out of it is remarkable! I can't remember the exact details, but the Mandlebrot application I mentioned above runs in right around 10 seconds when compiled with GCC. That's way faster than any other hardware that I have in my collection. That's using the EC 68000 at 28 or 29 MHz.

Roger
 
> try to compile-it also with the "optimization" flag

Ok, much better when using >htc -v -c -o -s hello.c
Code:
global  _main
global  ncsv, cret, indir
global  _printf
psect   text
_main:
ld      hl,19f
push    hl
call    _printf
pop     bc
ld      hl,0
ret
psect   data
19:
defb    72,101,108,108,111,10,0
psect   text
 
Last edited:
It may depend a lot on the compiler, and the target architecture. Some archs are better targets for C than others.

I do a lot of work with the Motorola 68000, and I use GCC to compile C for it, and I wouldnt have it any other way. A lot of the time, when I examine the disassembly, it does about as good a job as I might do by hand anyway. What ever small performance hit there may be isnt enough to make me want to ditch C outright.

I am much more productive writing C, but when I really want to do something my way I can use inline assembly or write a routine in assembly that I call from C. Best of both worlds.

But the 68000 is a much better target for C than, say, the Z80. Ive not tried to compile C for the Z80, but I suspect if I tried I'd be less than impressed with the results too.

You have to write C for the compiler with 8080 or Z80 which IMHO is problematic when the point is portability. The 8080 sucked at stack relative accesses and the Z80 added about a million mostly useless instructions but didn't fix the basics. The 8085 did - in about 4 instructions but Intel then decided not to document it.

That said if you profile a CP/M BIOS the amount of time it spends in there is miniscule and the number of hot paths is tiny just like any operating system. It's why Fuzix can be fast but in C even on 6502 or Z80. For most micros running classic disk operating environments everything comes down to "how fast can you get a block of disk data to the user", "how fast can you copy" and "how quick is your video/serial driver". And of course for Microsoft BASIC "how fast can you implement 'is there a key pending', to the point people use to micro-optimize that BIOS path to get better benchmarketing numbers.

Having written a compiler for the Z80 that fits in 64K the Z80 is IMHO very hard to write compilers for. It's got poor reg/mem operators, the register allocation problem is horrendous - and way beyond the kind of graphs you can compute in 64K. SDCC does compute full Z80 register allocation graphs much of the time but it's often using a gigabyte for it and the kind of compute that would historically have beeen supercomputing or beyond. 8085 is much nicer, 680x is nicer, even 6800 is nicer.
 
So... does anyone remember BDSC?
"Brain Dead Software" was the name of the company.
Integer only.
Caused me to buy Turbo Pascal for my Osborne at the time.
 
Yep! BDS C was one of the ones that I tested in my evaluation of various compilers. I don't remember now how I got around the lack of floating point. Maybe I had a later version with f.p.? Wasn't anywhere near the performance of HiTech. "Mr. BDS" used to joke (maybe it wasn't a real joke?) that "BD" stood for "Bad Drugs". I think he was a student, or maybe a graduate, of M.I.T.???

Roger
 
If we expand the topic to "Compilers for CP/M" (not only for C ...), there are some interesting news.
For example, consider the case of Cowgol... a new programming language specifically created by David Given for 8-bit computers.
I developed a CP/M hosted development environment intended to support building programs written in C, Cowgol and Z80 assembler (including projects mixing these languages).
As an example of using Cowgol to write CP/M utility programs: recently I published a binary editor, written in Cowgol, able to handle binary files with size up to 44 KB.
Why is this important? Because, this way, almost all existent CP/M COM files can be edited. The same tool, written in C, may edit only files with size up to 32 KB, (the C executable is much larger, compared with the Cowgol executable).
Ladislau
 
Back
Top