A Comparison of =========================================================== MM MM IIIIIII CCCC RRRRRR OOO CCCC M M M M I C C R R O O C C M M M I C R R O O C M M I C RRRRRR O O ----- C M M I C R R O O C M M I C C R R O O C C M M IIIIIII CCCC R R OOO CCCC =========================================================== A N D =========================================================== SSSSS MM MM A L L CCCC S S M M M M A A L L C C S M M M A A L L C SSSSS M M A A L L ----- C S M M AAAAAAA L L C S S M M A A L L C C SSSSS M M A A LLLLLLL LLLLLLL CCCC =========================================================== Copyright 1990-2005 Dave Dunfield All rights reserved MICRO-C .vs. SMALL-C TABLE OF CONTENTS Page 1. INTRODUCTION 1 2. DETAILED COMPARISON OF COMPILERS 1 2.1 'C' Implementation 2 2.2 Generated code quality 4 2.3 Speed of compilation 5 2.4 Timing the tests 6 2.5 Test results 7 3. OTHER ADVANTAGES OF MICRO-C 8 3.1 Utilities 8 3.2 Example Programs 8 MICRO-C .vs. SMALL-C Page: 1 1. INTRODUCTION A common reaction of people hearing about DDS MICRO-C for the first time is something like "Yeah right! ... this is probably just another version of the old SMALL-C compiler"... This couldn't be further from the truth. MICRO-C IS NOT SMALL-C!!! MICRO-C is a completely new implementation of a 'C' compiler suitable for use on very small systems. It was not based in any way on SMALL-C (in fact, I had not seen the SMALL-C sources when I first wrote Micro-C). Micro-C offers several advantages over SMALL-C: - It was designed from the ground up to be easily portable to different processors & computer platforms. Code generators are available for 8080, 8051, 80x86, 8096, 68HC08, 6809, 68HC11, 68HC12, 68HC16 and AVR cpu's, as well as a C-FLEA version which operates through a "virtual 16 bit machine" instruction set. Although SMALL-C claims to be easily portable, much of it's architecture is oriented toward the original 8080 processor. For an example of how this affects the compiler, compare the code generated by the 8086 version of SMALL-C to reference stack (auto) variables to that produced by MICRO-C. - It is a more complete implementation of the 'C' language, see the features comparison later in this document. - It produces faster, more compact code. See the benchmark results later in this document. - MICRO-C employs a fully tokenized parser, allowing statement analysis to be performed on integer "tokens" instead of text strings as is done in SMALL-C. This results in MUCH faster compilation. - Although it is higher in functionality than SMALL-C, the MICRO-C compiler is much smaller than SMALL-C (Nearly half the size). This allows it to run on very small computer systems. 2. DETAILED COMPARISON OF COMPILERS The following pages contain a detailed comparison of the SMALL-C version 2 compiler, and MICRO-C. MICRO-C .vs. SMALL-C Page: 2 2.1 'C' Implementation = Data Types ===========+ SMALL-C V1 + SMALL-C V2 + MICRO-C + int | Yes | Yes | Yes | char | Yes | Yes | Yes | unsigned int | No | No | Yes | unsigned char | No | No | Yes | long | No | No | Library | void | No | No | Yes | const | No | No | Yes | register | No | No | Yes | pointers | Yes | Yes | Yes | pointers to pointers | No | No | Yes | structs & unions | No | No | Yes | Single dimension arrays | Yes | Yes | Yes | Multi dimension arrays | No | No | Yes | Arrays of pointers | No | No | Yes | Arrays of structs | No | No | Yes | Typecast | No | No | Yes | sizeof | No | No | Yes | Static globals & locals | No | No | Yes | = Control Structures ===+ SMALL-C V1 + SMALL-C V2 + MICRO-C + if/else | Yes | Yes | Yes | while | Yes | Yes | Yes | do/while | No | Yes | Yes | for | No | Yes | Yes | switch/case | No | Yes | Yes | goto | No | Yes | Yes | Conditional Expressions | No | Yes | Yes | Inline assembly | Yes* | Yes* | Yes | = Pre-Processor ========+ SMALL-C V1 + SMALL-C V2 + MICRO-C + #define (basic) | Yes | Yes | Yes | #define (Parameterized) | No | No | Yes | #define (Multi-line) | No | No | Yes | #undef | No | No | Yes | #include (single level) | Yes | Yes | Yes | #include (nested) | No | Yes | Yes | #ifdef/#ifndef | No | Yes | Yes | #if/#elif | No | No | Yes | #else/#endif | No | Yes | Yes | #error | No | No | Yes | #file | No | No | Yes | #forget | No | No | Yes | #message | No | No | Yes | #index | No | No | Yes | String concatenation | No | No | Yes | __DATE__ | No | No | Yes | __FILE__ | No | No | Yes | __LINE__ | No | No | Yes | __TIME__ | No | No | Yes | __INDEX__ | No | No | Yes | = Misc features ========+ SMALL-C V1 + SMALL-C V2 + MICRO-C + Modern func. definitions| No | No | Yes | Optimization | No | Yes* | Yes | Multiple memory models | No | No | Yes | Make/touch utility | No | No | Yes | Source linker | No | No | Yes | Integ. Dev. Environment | No | No | Yes | MICRO-C .vs. SMALL-C Page: 3 C++ style comments | No | No | Yes | 68HC08 code generator | No | No | Yes | 6809 code generator | No | No | Yes | 68HC11 code generator | No | No | Yes | 68HC12 code generator | No | No | Yes | 68HC16 code generator | No | No | Yes | 8080 code generator | Yes* | Yes* | Yes | 8051 code generator | No | No | Yes | 8086 code generator | No | Yes* | Yes | 8096 code generator | No | No | Yes | AVR code generator | No | No | Yes | C-FLEA code generator | No | No | Yes | Complete standard lib | No | Yes* | Yes | Interrupt serial I/O | No | No | Yes | Windowing library | No | No | Yes | TSR support | No | No | Yes | Graphics library | No | No | Yes | * - Denotes features which although available in SMALL-C, are superior in the MICRO-C implementation. MICRO-C .vs. SMALL-C Page: 4 2.2 Generated code quality [Note, this comparison was last performed in 1993 using Micro-C 2.41... Micro-C has progressed considerably beyond this now (there have been more than a dozen new versions released since then), and the gap has between these two compiler has widened to the point where it makes no sense to keep testing.] To test the actual performance of code generated by MICRO-C against code generated by SMALL-C (v2.1), I used this "Sieve of Eratosthenes" prime number generator program, taken from the BYTE benchmarks: /* * The classic "Sieve of Eratosthenes" prime number program. * from BYTE, January 1983. */ #include #include "timer.c" /* The timer subroutines */ #define SIZE 8190 #define LOOP 100 #define TRUE 1 #define FALSE 0 char flags [SIZE + 1]; main() { int i, prime, k, count, iter; printf("BYTE Sieve Benchmark - %d iterations\n",LOOP); /* Start timer and execute loop */ startimer(timestamp); for(iter = 1; iter <= LOOP; ++iter) { count = 0; /* prime counter */ for(i = 0; i <= SIZE; ++i) /* set all flags true */ flags [i] = TRUE; for(i = 0; i <= SIZE; ++i) { if(flags [i]) { /* found a prime */ prime = i + i + 3; /* twice index + 3 */ /* printf ("\n%d", prime); */ for(k = i + prime; k <= SIZE; k+= prime) flags [k] = FALSE; /* kill all multiple */ ++count; } } } /* primes found */ elapsed(timestamp); /* Calculate time taken */ /* Report results */ printf("%d primes.\n\n", count); /* primes found on 100th pass */ printf("Elapsed time: %02d:%02d:%02d.%02d\n", timestamp[1], timestamp[0], timestamp[3], timestamp[2]); } MICRO-C .vs. SMALL-C Page: 5 2.3 Speed of compilation To show the relative compilation times, I wrote this simple MICRO-C program, using the timing routines shown below, to execute the compilers & report the time taken: #include #include "timer.c" /* The timer subroutines */ main() { startimer(timestamp); system("CC SIEVE"); /* Execute the SMALL-C compiler */ elapsed(timestamp); printf("Elapsed time: %02d:%02d:%02d.%02d\n\n", timestamp[1], timestamp[0], timestamp[3], timestamp[2]); startimer(timestamp); system("MCC SIEVE.C SIEVE.ASM");/* Execute the MICRO-C compiler */ elapsed(timestamp); printf("Elapsed time: %02d:%02d:%02d.%02d\n", timestamp[1], timestamp[0], timestamp[3], timestamp[2]); } NOTE: The results from the above program will include the time taken to load the compilers. To minimize this, all tests were run from a RAMdisk. This eliminates disk seek time, and reduces load time to the speed of a memory to memory copy. MICRO-C .vs. SMALL-C Page: 6 2.4 Timing the tests These subroutines were used to time the programs, using the MS-DOS internal clock which has a resolution of 1/100 of a second: char timestamp[4]; /* Stores initial timestamp */ /* * Record system time for later calculation */ startimer() asm { MOV AH,2CH ; Get time function INT 21H ; Ask DOS MOV SI,4[BP] ; Get pointer to timestamp MOV [SI],CX ; Record hours & minutes MOV 2[SI],DX ; Record seconds & hundreds } /* * Calculate elapsed time since timestamp recorded */ elapsed() asm { MOV AH,2CH ; Get time function INT 21H ; Ask DOS MOV SI,4[BP] ; Pointer to timestamp SUB DL,2[SI] ; Convert 100ths JNC ELAP1 ; No borrow ADD DL,100 ; readjust DEC DH ; Reduce seconds ELAP1: MOV 2[SI],DL ; Save elapsed hundreds SUB DH,3[SI] ; Convert seconds JNS ELAP2 ; No borrow ADD DH,60 ; Readjust DEC CL ; Reduce minutes ELAP2: MOV 3[SI],DH ; Save elapsed seconds SUB CL,[SI] ; Convert minutes JNS ELAP3 ; No borrow ADD CL,60 ; Readjust DEC CH ; Adjust hours ELAP3: MOV [SI],CL ; Save elapsed minutes SUB CH,1[SI] ; Convert hours MOV 1[SI],CH ; Save elapsed hours } MICRO-C .vs. SMALL-C Page: 7 2.5 Test results After compiling the programs, I ran the various tests on a standard 8-Mhz IBM PC/AT, with these results: E:\>dir Volume in drive E is VDISK V3.3 Directory of E:\ CC EXE 40626 4-27-93 /* SMALL-C compiler */ MCC COM 24154 4-27-93 /* MICRO-C compiler */ TIMER C 1094 4-27-93 /* The timer subroutines */ TIMECOMP C 527 4-27-93 /* The compiler timer */ SIEVE C 1149 4-27-93 /* The test program */ SIEVE-S EXE 16946 4-27-93 /* SMALL-C produced this */ SIEVE-M COM 1744 4-27-93 /* MICRO-C produced this */ TIMECOMP COM 1908 4-27-93 /* Executable compiler timer */ 8 File(s) 430080 bytes free E:\>sieve-s /* The SMALL-C version: 1 min, 28.98 secs */ BYTE Sieve Benchmark - 100 iterations 1899 primes. Elapsed time: 00:01:28.98 E:\>sieve-m /* The MICRO-C version: 0 min, 40.43 secs */ BYTE Sieve Benchmark - 100 iterations 1899 primes. Elapsed time: 00:00:40.43 E:\> **NOTE: Before running TIMECOMP, I created a "generic" STDIO.H file which was suitable for both compilers. E:\>timecomp /* Times to compile the program */ Small-C Compiler, Version 2.1, (Rev. 75) Copyright 1982, 1983, 1985 J. E. Hendrix Elapsed time: 00:00:04.72 /* SMALL-C 4.72 secs */ MICRO-C Compiler Copyright 1988-2005 Dave Dunfield All rights reserved. Elapsed time: 00:00:01.15 /* MICRO-C 1.15 secs */ E:\> MICRO-C .vs. SMALL-C Page: 8 3. OTHER ADVANTAGES OF MICRO-C In addition to being a superior and more portable compiler, The MICRO-C package also offers these advantages: 3.1 Utilities MICRO-C Comes with the following utilities: CC - Command Coordinator, combines pre-processor, compiler, optimizer, assembler and linker into a single command. Command line parameters allow very flexible operation. MAKE - Automates building of larger (multi module) programs. TOUCH - Set timestamp of file to current or specified date. (Used with MAKEs dependency checking) SLINK - Source LINKer, Allows pre-compiled (assembler) source to be kept in a library and included as needed to resolve external references. Useful when MICRO-C is used as cross compiler for systems not supporting an object linker. SLIB - Utility for updating and maintaining a source library. SINDEX - Automatically indexes a source library for use by SLINK. SCONVERT- Converts assembly language source for use by SLINK. EXE2BIN - Converts MS-DOS EXE files to a binary image, useful for users of later versions of DOS which no longer include this utility. MCP - The MICRO-C Pre-processor MCC - The MICRO-C Compiler MCO - The MICRO-C Optimizer DDSIDE - Integrated Development Environment SPRITED - Sprite editor for the graphics library ..more.. - Additional utilities not listed here 3.2 Example Programs MICRO-C comes with a very large collection of example programs (more than 130 program, all with complete Micro-C source). For a complete list, please refer to the README file supplied with the Micro-C examples directory.