The C99C compiler for the PC and optimizers are part of the development
environment of the TI994W emulator and can
be found in the utility directory TI994W/UTL/.
|
Introduction
This page gives a description of the C99 Compiler environment I use on my PC for
creating programs for the TI99/4A home computer. The C99 compiler with the C99
optimizers, Xa99 cross assembler and L99 linker forms a simple environment. The
optimizers were written to be able to create and shrink programs like DM2K and
DU2K so that programs like this can be used on a standard TI99/4A.
|
Current versions:
C99C - V 5.1.1 Clint Pulley's C99 compiler (until version 4.0)
C99O - V 5.6.1 Base optimizer
C99M - V 1.2.0 Move Instruction Optimizer
C99X - V 1.4.7 X-File optimizer
C99F - V 2.1.1 Function call and Jump optimizer
C99Z - V 1.1.1 Final optimizer
|
C99C - C Compiler
C99C is the PC version of the C99C compiler for the TI99/4A home computer
written by Clint Pulley. This X-compiler version of C99 is based on the
source code release of 91/02/23 and was created somewhere in 2002.
4.0 1987/10/24 - Final 99/4A version.
- Reports lines processed, global and local symbol counts.
- Implements hex constants.
- Issues "call files(3)" during initialization.
- Corrects problem with decimal input.
4.1.0 2002/00/00 FGK - Created a C99C WIN32 console program :-)
4.1.0 2006/00/00 FGK - Fixed some runtime problems because of using uninitialized variables.
4.1.2 2021/05/02 FGK - Fixed some problems so that C99C can be used with make.
Increased MACQSIZE from 1000 to 2000.
4.2.1 2023/01/02 FGK - Global symbol names converted to uppercase to prevent
problems when unintentionally cases are mixed which could
generate the wrong code, i.e. LI 8,NAME instead of MOV @NAME,8
(must be uppercase for the assembler anyway).
5.1.1 2023/01/04 FGK - Added assignment operators +=, -=, &=, |=, *=, /=, %=, <<= and >>=
Allow // for single line comment.
Added void type (handled as an int).
Added new style function declarations like type function(type args);
Added function prototyping:
o entry type function(type arg, type arg);
o static type function(type arg, type arg);
o extern type function(type arg, type arg);
and also variable argument list is allowed, like:
o int printf(char *fmt, ...);
type can be char, char *, int, int * or void which is handled like an
int.
Return type is not checked but is there to help you ... the programmer.
When a function is called the number of arguments is checked. In the
case of a variable argument list the minimum number of arguments is
checked. An error is issued when number of arguments does not match.
Usage: C99 inputfile outputfile [errorfile] [/tp]
Options:
/t Keep original C-source line as comment in assembler code
/p Generate inline push-code
/s Add global symbol table dump to error file (since 5.1.1)
The C99 compiler generates ready to assemble code wich can be linked together
with supplied libraries (like CSUP, file-IO etc) or your own created libraries
to an running editor/assembler option 5 program for the TI99/4A.
|
C99O - C Optimizer
The C99O optimizer is the PC version of the optimizer originally supplied by the
first version of the C99 compiler. This program started as a version for for the
Geneve to run under MDOS and more and more optimizations where added over the
years. Everytime I studied the assembler code created I saw something new to
optimize.
*c99 optimizer v4.5/g
Usage: C99O inputfile outputfile
The original version of C99O only optimized code for simple assignment
statements like A=B but this version of C990 optimizes every obvious assembler
code that looks like it can be done simpler, like A=B&C, A=B|C, switch(A), if
(A==B), etc, etc, etc.
Using this optimizer results in a smaller (and faster) program.
Here below you will see some examples how C99C code is optimized by C99O:
|
C99C C99O
========================= =========================
*key=10;
MOV 14,8 LI 8,10
AI 8,12 MOV 8,@12(14)
BL 15
LI 8,10
MOV *14+,9
MOV 8,*9
*switch(key)
MOV 14,8 MOV @12(14),8
AI 8,12 B @C$6
MOV *8,8
B @C$6
*Qftype = Qfparm & M_FTYP;
MOV @QFPARM,8 MOV @QFPARM,8
BL 15 ANDI 8,15
LI 8,15 MOV 8,@QFTYPE
INV *14
SZC *14+,8
MOV 8,@QFTYPE
*Qfparm = Qftype | Qfprot | Qfslct;
MOV @QFTYPE,8 MOV @QFTYPE,8
BL 15 SOC @QFPROT,8
MOV @QFPROT,8 SOC @QFSLCT,8
SOC *14+,8 MOV 8,@QFPARM
BL 15
MOV @QFSLCT,8
SOC *14+,8
MOV 8,@QFPARM
*newname[0] = 0;
MOV 14,8 MOV 14,8
BL 15 MOV 8,9
S 8,8 S 8,8
A *14+,8 MOVB *10,*9
BL 15
S 8,8
MOV *14+,9
MOVB *10,*9
|
C99X - X File Optimizer
The C99X - X File Optimizer replaces calls to standard C-functions like gets(),
puts(), putchar(), locate(), poll() and tscrn() and all string and memory
funtions like strcpy(), strlen(), strcat(), strcmp(), memset(), memcpy()
for witch the arguments are placed on the C-stack first to the functions
XGETS(), XPUTS(), XPUTC(), XLOCAT(), XPOLL(), XTSRCN(), XSCPY(), XSLEN(),
XSCAT(), XSCMP(), XMSET(), XMCPY(), XMMOV() if possible but
arguments are placed in registers. The code for placing the arguments on the C-
stack is removed together with the code (or instruction) to clean-up the C-
stack. I found that the first thing these standard C-functions do is reading the
values from the C-stack and placing them in registers making the code (IMHO) for
placing the arguments on the stack and cleaning the stack unnecessary. Replacing
these function calls can only succeed if the arguments are in their most simple
form, like FUNCTION(A,B) and not like FUNCTION(A+B,C*D). To use this optimizer
an updated CSUP (CSUPTI_V7) must be used.
Using this optimizer results in a smaller (and faster) program.
*c99 x-optimizer v1.4/g
Usage: C99X inputfile outputfile
Here below you will see some examples how C99C code is optimized by C99X:
|
C99C C99X
========================= =========================
*locate(ypos,1);
MOV @YPOS,8 MOV @YPOS,1
BL 15 LI 0,1
LI 8,1 BL *12
BL 15 DATA XLOCAT
BL *12
DATA LOCATE
AI 14,4
*locate(y,x);
MOV @58(14),8 MOV @58(14),1
BL 15 MOV @62-2(14),0
MOV @62(14),8 BL *12
BL 15 DATA XLOCAT
BL *12
DATA LOCATE
AI 14,4
*putchar('>');
LI 8,62 LI 1,62
BL 15 BL *12
BL *12 DATA XPUTC
DATA PUTCHA
INCT 14
*strcpy(Srcfil,Src);
LI 8,SRCFIL LI 1,SRCFIL
BL 15 LI 2,SRC
LI 8,SRC BL *12
BL 15 DATA XSCPY
BL *12
DATA STRCPY
AI 14,4
*strcat(Srcfil,Pfname);
LI 8,SRCFIL LI 0,SRCFIL
BL 15 MOV @PFNAME,1
MOV @PFNAME,8 BL *12
BL 15 DATA XSCAT
BL *12
DATA STRCAT
AI 14,4
|
C99F - Function Call Optimizer
The C99F - Function Call Optimizer replaces the code for storing function
arguments on the C-stack for code that store the arguments in registers (R0-R8)
and a call to a function (FARG#1 through FAARG#8) that will store all these
register values on the C-stack. This optimization can only succeed for functions
with 1 through 8 arguments and the arguments are in their most simple form, like
FUNCTION(A,B) and not like FUNCTION(A+B,C*D). To use this optimizer the library
FNCARG must be linked.
The C99F optimizer also optimizes compare instuctions by replacing a branch to a
compare subroutine by a TMS9900 compare instruction wherever possible. The C99F
optimizer checks if the destination of the jump is within some amount of
instructions.
Using this optimizer and library results in a smaller (and not necessary faster) program.
*c99 f-optimizer v1.3/g
Usage: C99F inputfile outputfile
Here below you will see some examples how C99C code is optimized by C99F:
|
C99C C99F
========================= =========================
*setkbm(5);
LI 8,5 LI 8,5
BL 15 BL @FARG#1
BL *12 DATA SETKBM
DATA SETKBM INCT 14
INCT 14
*getfps(FilesP, pFile);
MOV @FILESP,8 MOV @FILESP,7
BL 15 MOV @PFILE,8
MOV @PFILE,8 BL @FARG#2
BL 15 DATA GETFPS
BL *12 AI 14,4
DATA GETFPS
AI 14,4
*key = answer("Exit program? ([y],n) ",0);
MOV 14,8 MOV 14,6
AI 8,12 AI 6,12
BL 15 LI 7,C$1
LI 8,C$1 S 8,8
BL 15 BL @FARG#3
S 8,8 DATA ANSWER
BL 15 AI 14,4
BL *12 MOV *14+,9
DATA ANSWER MOV 8,*9
AI 14,4
MOV *14+,9
MOV 8,*9
*if (Qftype<=FT_SUB) [Label C$20 within range for sure]
MOV @QFTYPE,8 MOV @QFTYPE,8
BL 15 CI 8,6
LI 8,6 JGT C$20
BL @C$LE
JNE $+6
B @C$20
*if (Qftype<=FT_SUB) [Label C$8 maybe out of range]
MOV @QFTYPE,8 MOV @QFTYPE,8
BL 15 CI 8,6
LI 8,6 JLT $+8
BL @C$LE JEQ $+6
JNE $+6 B @C$8
B @C$8
|
C99M - Move Instruction Optimizer
The C99M - Move Instruction Optimizer is capable in optimizing certain MOV
instructions in the assembler code as generated by the C99O optimizer.
Using this optimizer results in a smaller (and faster) program.
*c99 m-optimizer v1.1/g
Usage: C99M inputfile outputfile
Here below you will see some examples how C99C code is optimized by C99O and
c99O code code is optimized by C99M:
|
C99C C99O C99M
========================= ========================= =========================
*for (...; ...; i=i+1)
MOV 14,8 MOV 14,8 MOV 14,9
BL 15 BL 15 MOV *9,8
MOV 14,8 MOV @2(14),8 AI 8,1
INCT 8 AI 8,1 MOV 8,*9
MOV *8,8 MOV *14+,9
BL 15 MOV 8,*9
LI 8,1
A *14+,8
MOV *14+,9
MOV 8,*9
*sx = x+p;
MOV 14,8 MOV 14,8 MOV 14,9
AI 8,10 AI 8,10 AI 9,10
BL 15 BL 15 MOV @24(14),8
MOV 14,8 MOV @26(14),8 A @4(14),8
AI 8,26 A @8-2(14),8 MOV 8,*9
MOV *8,8 MOV *14+,9
BL 15 MOV 8,*9
MOV 14,8
AI 8,8
MOV *8,8
A *14+,8
MOV *14+,9
MOV 8,*9
|
C99Z - Final Optimizer
The C99Z - Final Instruction Optimizer optimizes assignments, compares
instructions in the assembler code as generated by the C99O / C99M and C99F
optimizers. This optimizer searches for those instructions that loads R8 with
a value and then compares this value with zero (CI 8,0) or determine the absolute
value (ABS 8) followed by some JMP instruction. Then this CI or ABS instruction
is unnecessary. Another optimization is some assignment using R8 as an
intermediant register (MOV x,8 and MOV 8,y). This is unnecessary if R8 is used
again in the next instuction and the two MOV instructions are replaced by
one MOV x,y instruction. Onother optimization is when the address
of a variable is determined using R8 and this address is directly moved to R9
followed by determining the value for this same variable using R8. This is replaced
by the determining the addres of the variable directly in R9.
Using this optimizer results in a smaller (and faster) program.
*c99 z-optimizer v1.1/g
Usage: C99Z inputfile outputfile
Here below you will see some examples how C99C code is optimized by C99O and C99Z:
|
C99C C99O C99F C99Z
========================= ================ ================ ================
*if (dbuf == 0) ...
MOV @DBUF,8 MOV @DBUF,8 MOV @DBUF,8 MOV @DBUF,8
BL 15 BL 15 CI 8,0 JNE C$6
S 8,8 S 8,8 JNE C$6
BL @C$EQ BL @C$EQ
JNE $+6 JNE $+6
B @C$6 B @C$6 <- Label C$6 is in reach of JMP
*FilesT = FilesP;
MOV @FILESP,8 MOV @FILESP,8 MOV @FILESP,8 MOV @FILESP,@FILEST
MOV 8,@FILEST MOV 8,@FILEST MOV 8,@FILEST
*
MOV @REFRES,8 <- R8 is used in the next instruction
*newname[0] = 0;
MOV 14,8 MOV 14,8 MOV 14,8 MOV 14,9
INCT 8 INCT 8 INCT 8 INCT 9
BL 15 MOV 8,9 MOV 8,9 S 8,8
S 8,8 S 8,8 S 8,8 MOV *10,*9
A *14+,8 MOVB *10,*9 MOVB *10,*9
BL 15
S 8,8
MOV *14+,9
MOVB *10,*9
|