1
0
mirror of https://github.com/cc65/cc65.git synced 2024-12-26 08:32:00 +00:00

support for VLIR structured files when using ca65 only

git-svn-id: svn://svn.cc65.org/cc65/trunk@1340 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
izydorst 2002-07-10 18:43:04 +00:00
parent da3baace1f
commit a152fe71c5
3 changed files with 263 additions and 30 deletions

View File

@ -3,11 +3,11 @@
grc - GEOS resource compiler
Maciej 'YTM/Alliance' Witkowiak
<ytm@friko.onet.pl>
Maciej 'YTM/Elysium' Witkowiak
<ytm@elysium.pl>
VII 2000
VI 2002
@ -22,13 +22,16 @@ menu definitions, other headers (e.g. for data files of an app), dialogs
definitions etc. Without application header GEOS is unable to load and start
it.
Currently, grc supports only menus and required header definition.
Currently, grc supports only menus and required header definition as long with
support for building VLIR structured files.
grc generates output in two formats - as C header and ca65 source (.s). This
is because application header data must be in assembler format while menu
definitions can be easily translated into C. The purpose of C file is to include
it as header in only one project file. Assembler source should be processed with
ca65 and linked as first object (read Building process below).
grc generates output in three formats - as C header, ca65 source (.s) and for
linking VLIR - ld65 configuration file. This is because application header data
must be in assembler format while menu definitions can be easily translated
into C. The purpose of C file is to include it as header in only one project
file. Assembler source should be processed with ca65 and linked as first object
(read Building process below). VLIR structure is currently supported only for
project written entirely in assembler.
2. Usage
--------
@ -37,13 +40,14 @@ grc accepts following options:
-f force writting output files
-o name name C output file
-s name name S output file
-l name name ld65 output file
-h help
Default output names are made from input name with extension replaced by '.h'
and '.s'. grc will not overwrite existing files unless forced to do so.
This is to avoid situation where you have test.c and test.grc files. Both would
make output into test.s. For this reason you should name your resources files
differently than sources, e.g. as resource.grc or apphead.grc
differently than sources, e.g. as resource.grc or apphead.grc.
3. Resource file format
@ -57,7 +61,6 @@ Everything after a ';' till the end of line is considered as comment and
ignored.
See included commented example .grc file for better view of the problem.
Currently grc supports only two types of resources - menu and header.
a) menu definition
@ -90,6 +93,7 @@ or to another menu definition.
If you are doing sub(sub)menus definitions remember to place the lowest level
definition first. This way C compiler won't complain about unknown names.
b) header definition
HEADER GEOS_TYPE "dosname" "classname" "version"
@ -99,6 +103,7 @@ HEADER GEOS_TYPE "dosname" "classname" "version"
date yy mm dd hh ss
dostype SEQ
mode any
structure SEQ
}
Header definition describes GEOS header sector which is unique to each file.
@ -121,9 +126,39 @@ Mode can be 'any', '40only', '80only', 'c64only' and describes system
requirements. 'any' will work both on GEOS64 and GEOS128 in 40 and 80 column
modes. '40only' will work on GEOS128 in 40 column mode only. '80only' will
work only on GEOS128 and 'c64only' will work only on GEOS64.
The default value for 'structure' is SEQ (sequential). You can also put 'VLIR'
there but then you have also to place third type of resources - VLIR table
description.
4. Building GEOS application
c) VLIR table description
VLIR headname address {
vlir0
blank
vlir2
blank
vlir4
}
The first element is keyword 'VLIR', then goes the name for header binary name
(read below) and base address for all VLIR chains diffrent than 0. It can be
either decimal (e.g. '4096') or hexadecimal with '0x' prefix (e.g. '0x1000').
Then between brackets are names of vlir chain binaries or keyword 'blank' which
denotes empty chains. In this example chains #1 and #3 are missing.
The names between brackets are names of binaries containing code for each VLIR
part. They matter only for generated ld65 configuration file and will be the
names of resulting binary files after linking. Each one will contain one VLIR
chain and they will have to be put together into VLIR .cvt by vlink utility in
correct order.
The 'headname' will be the name for binary which will contain only GEOS .cvt
header made out of compiling .s header file generated also by grc.
At the end of resulting ld65 config file (.cfg) in comments there will be
information what commands are required for putting the stuff together. Read
info below and see example somewhere around.
4. Building GEOS application (SEQUENTIAL)
----------------------------
Before proceeding please read cc65, ca65 and ld65 documentation and find
@ -191,7 +226,7 @@ And voil
4. Fourth and the last step - linking it together
$ ld -t geos -o test.cvt resource.o geos.o test.o geos.lib
$ ld65 -t geos -o test.cvt resource.o geos.o test.o geos.lib
resource.o comes first because it contains the header. Next one is geos.o, a
required starter code, then actual application code in test.o and the last is
@ -204,7 +239,64 @@ On each step a '-t geos' was present at the command line. This switch is require
for correct process of app building.
5. Bugs and feedback
5. Building GEOS application (VLIR)
-----------------------------------
Currently you can only build VLIR application if your code is written in
assembler. No .c allowed.
In your sources only command '.segment "NAME"' will decide which code/data goes
where. Filenames doesn't matter.
Segments CODE, RODATA, DATA and BSS go into VLIR part #0. Segment VLIR1 go to
VLIR part #1, VLIR2 - VLIR part #2 and so on.
GEOS resource file contents are similar to seq example but there is also 'VLIR'
section and 'structure VLIR' tag. Here is that part:
VLIR vlir-head.bin 0x3000 {
vlir-0.bin ; CODE, RODATA, DATA, BSS
vlir-1.bin ; VLIR1
vlir-2.bin ; VLIR2
}
Source files are only .s.
Ok. We have 'cvthead.grc' so let's allow grc to compile it:
$ grc cvthead.grc
Now there are two new files: cvthead.cfg and cvthead.s - the first one is a
config file for ld65 and the second one contains GEOS .cvt header. It can be
assembled now:
$ ca65 cvthead.s
Now we have cvthead.o. The rest of assembly sources can be also assembled now:
$ ca65 vlir0.s
$ ca65 vlir1.s
$ ca65 vlir2.s
Note that filenames here although similar to those from VLIR section of .grc file
are not significant. The only thing that matters is which code will go to which
segment.
Now we can generate binaries. This time order of arguments in command line is
not important.
$ ld65 -C cvthead.cfg cvthead.o vlir0.o vlir1.o vlir2.o
As defined in .grc file, we have now binary parts of VLIR file:
vlir-head.bin, vlir-0.bin, vilr-1.bin, vlir-2.bin
The last step is to put them together in the right order, order of arguments
is important this time. As suggested in comments at the end of cvthead.cfg
we do:
$ vlink output.cvt vlir-head.bin vlir-0.bin vlir-1.bin vlir-2.bin
This is the end. The file 'output.cvt' can be unconverted under GEOS.
Note that the switch '-t geos' wasn't present at any stage of this process.
6. Bugs and feedback
--------------------
This is the first release of grc and it contains bugs for sure. I am aware of
@ -216,7 +308,7 @@ I would also appreciate comments and help on this file because I am sure that
it can be written better.
6. Legal stuff
7. Legal stuff
--------------
grc is covered by the same license as whole cc65 package, so see its
@ -268,6 +360,7 @@ HEADER APPLICATION "MyFirstApp" "Class Name" "V1.0"
info "Information text" ; always in quotes!
; date yy mm dd hh ss ; always 5 fields!
; dostype seq ; can be PRG, SEQ, USR (only UPPER or lower case)
; structure seq ; can be SEQ, VLIR (only UPPER or lower case)
mode c64only ; can be any, 40only, 80only, c64only
}

View File

@ -2,7 +2,7 @@
/*
GEOS resource compiler
by Maciej 'YTM/Alliance' Witkowiak
by Maciej 'YTM/Elysium' Witkowiak
Error function by Uz
@ -59,6 +59,15 @@ void printSHeader (void) {
"\n;\n\n");
}
void printVHeader (void) {
fprintf(outputVFile, "\n#\n#\tThis file was generated by GEOS Resource Compiler\n#"
"\n#\tDO NOT EDIT! Any changes will be lost!\n#"
"\n#\tEdit proper resource file instead\n#"
"\n#\tLook at end of this file to find commandline that must be used\n"
"#\tto invoke ld65 and vlink\n#"
"\n#\n\n");
}
void openCFile (void) {
if ((CFnum==0) && (forceFlag==0)) {
/* test if file exists already and no forcing*/
@ -81,13 +90,25 @@ void openSFile (void) {
if (SFnum==0) { outputSMode[0]='a'; printSHeader(); SFnum++; }
}
void openVFile (void) {
if ((VFnum==0) && (forceFlag==0)) {
/* test if file exists already and no forcing*/
if ((outputVFile = fopen (outputVName,"r"))!=0)
Error("file %s already exists, no forcing, aborting\n", outputVName);
}
if ((outputVFile = fopen (outputVName,outputVMode))==0)
Error("can't open file %s for writting: %s\n",outputVName,strerror (errno));
if (VFnum==0) { outputVMode[0]='a'; printVHeader(); VFnum++; }
}
void printUsage (void) {
fprintf(stderr, "Usage: %s [options] file\n"
"Options:\n"
"\t-h, -?\t\tthis help\n"
"\t-f\t\tforce writting files\n"
"\t-o name\t\tname C output file\n"
"\t-s name\t\tname asm output file\n",
"\t-s name\t\tname asm output file\n"
"\t-l name\t\tname ld65 config output file (for vlir)\n",
progName);
}
@ -277,6 +298,7 @@ int a, b;
myHead.author = "cc65";
myHead.info = "Program compiled with cc65 and GEOSLib.";
myHead.dostype = 128+3;
myHead.structure = 0;
myHead.mode = 0;
t = time(NULL);
@ -334,6 +356,18 @@ int a, b;
myHead.mode = 0x80; break;
}
break;
case 5: /* structure */
switch (b = findToken(hdrStructTp, nextWord())) {
case -1:
Error ("unknown structure type in header %s\n", myHead.dosname);
case 0:
case 1:
myHead.structure = 0; break;
case 2:
case 3:
myHead.structure = 1; break;
}
break;
}
} while (strcmp(token, "}")!=0);
@ -346,11 +380,11 @@ int a, b;
fillOut(myHead.dosname,16,"$a0");
fprintf(outputSFile,
".word 0\n\t\t.byte 0\n\t\t.byte %i\n\t\t.byte %i, %i, %i, %i, %i\n\n\t\t"
".word 0\n\t\t.byte %i\n\t\t.byte %i\n\t\t.byte %i, %i, %i, %i, %i\n\n\t\t"
".word 0\n\t\t.byte \"PRG formatted GEOS file V1.0\"\n\n\t\t.res $c4\n\n\t\t"
".byte 3, 21, 63 | $80\n\t\t",
myHead.geostype, myHead.year, myHead.month, myHead.day, myHead.hour,
myHead.min);
myHead.structure, myHead.geostype, myHead.year, myHead.month, myHead.day,
myHead.hour, myHead.min);
for (a=0;a!=63;a=a+3) {
fprintf(outputSFile,
@ -358,8 +392,8 @@ int a, b;
bintos(icon1[a], i1), bintos(icon1[a+1], i2), bintos(icon1[a+2], i3)); };
fprintf(outputSFile,
"\n\t\t.byte %i, %i, 0\n\t\t.word $0400, $0400-1, $0400\n\n\t\t",
myHead.dostype, myHead.geostype);
"\n\t\t.byte %i, %i, %i\n\t\t.word $0400, $0400-1, $0400\n\n\t\t",
myHead.dostype, myHead.geostype, myHead.structure);
fillOut(myHead.classname,12,"$20");
@ -384,6 +418,89 @@ int a, b;
}
void DoVLIR (void) {
char *token;
char *headname;
int i,numchains,vlirbase;
struct vlirentry {
char *chainname;
int exist;
};
struct vlirentry vlirtable[127];
openVFile();
headname = nextWord();
vlirbase = strtol(nextWord(),NULL,0);
if (strcmp(nextWord(),"{")!=0) {
Error ("VLIR description has no opening bracket!\n");
};
numchains=0;
do {
token=nextWord();
if (strcmp(token, "}")==0) break;
numchains++;
if (numchains>127) {
Error("Too many VLIR chains!\n");
}
vlirtable[numchains].chainname=token;
/* for first chain - name header */
if (numchains==1) {
fprintf(outputVFile,"MEMORY {\n\tHEADER: start = $204, size = 508, file = \"%s\";\n"
"\tVLIR0: start = $0400, size = $5C00, file = \"%s\";\n",headname,token);
} else {
/* for all other - segment */
/* ignore non-existing segments */
vlirtable[numchains].exist=1;
if ( (strcmp(token,"blank")==0) || (strcmp(token,"noexist")==0) ) {
vlirtable[numchains].exist=0;
fprintf(outputVFile,"#");
}
fprintf(outputVFile,"\tVLIR%i: start = $%x, size = $%x, file = \"%s\";\n",
numchains-1,vlirbase,0x5c00-vlirbase,token);
}
} while (strcmp(token, "}")!=0);
fprintf(outputVFile,"}\n\n");
if (numchains==0) {
Error("There must be at least one VLIR chain.\n");
};
/* now put segments info */
fprintf(outputVFile,"SEGMENTS {\n\tHEADER: load = HEADER, type = ro;\n"
"\tCODE: load = VLIR0, type = ro;\n"
"\tRODATA: load = VLIR0, type = ro;\n"
"\tDATA: load = VLIR0, type = rw;\n"
"\tBSS: load = VLIR0, type = bss, define = yes;\n\n");
for (i=2;i<=numchains;i++) {
if (vlirtable[i].exist==0) {
fprintf(outputVFile,"#");
}
fprintf(outputVFile,"\tVLIR%i: load = VLIR%i, type = rw, define = yes;\n",i-1,i-1);
}
fprintf(outputVFile,"}\n");
/* now put usage info */
fprintf(outputVFile,"\n# ld65 -o output.cvt -C %s file1.o file2.o ...",outputVName);
fprintf(outputVFile,"\n# vlink outputname %s",headname);
for (i=1;i<=numchains;i++) {
fprintf(outputVFile," %s",vlirtable[i].chainname);
}
fprintf(outputVFile,"\n");
if (fclose (outputVFile)!=0)
Error("error closing %s: %s\n",outputVName,strerror (errno));
}
char *filterInput (FILE *F, char *tbl) {
/* loads file into buffer filtering it out */
int a, prevchar=-1, i=0, bracket=0, quote=1;
@ -419,7 +536,8 @@ FILE *F;
char *str;
char *token;
int head=0;
int head=0; /* number of processed HEADER sections */
int vlir=0; /* number of processed VLIR sections */
if ((F = fopen (filename,"r"))==0)
Error("can't open file %s for reading: %s\n",filename,strerror (errno));
@ -440,8 +558,15 @@ int head=0;
DoHeader();
}
break;
case 2: break;
case 3: break;
case 2: break; /* icon not implemented yet */
case 3: break; /* dialog not implemented yet */
case 4:
if (++vlir!=1) {
Error ("more than one VLIR section, aborting.\n");
} else {
DoVLIR();
}
break;
default: Error ("unknown section %s.\n",token); break;
}
}
@ -468,6 +593,9 @@ char *p, *tmp;
case 's':
outputSName=argv[++i];
break;
case 'l':
outputVName=argv[++i];
break;
case 'h':
case '?':
printUsage();
@ -498,6 +626,13 @@ char *p, *tmp;
}
if (outputVName==NULL) {
outputVName = malloc(strlen(arg));
strcpy (outputVName, tmp);
strcat (outputVName, ".cfg");
}
processFile(arg);
}

View File

@ -20,6 +20,7 @@ struct appheader {
int mode;
int dostype;
int geostype;
int structure;
char *dosname;
char *classname;
char *version;
@ -27,17 +28,20 @@ struct appheader {
char *info; };
const char *mainToken[] = {
"MENU", "HEADER", "ICON", "DIALOG", "" };
"MENU", "HEADER", "ICON", "DIALOG", "VLIR", "" };
const char *hdrFTypes[] = {
"APPLICATION", "AUTO_EXEC", "DESK_ACC", "ASSEMBLY", "DISK_DEVICE", "PRINTER", "SYSTEM", "" };
const char *hdrFields[] = {
"author", "info", "date", "dostype", "mode", "" };
"author", "info", "date", "dostype", "mode", "structure", "" };
const char *hdrDOSTp[] = {
"seq", "SEQ", "prg", "PRG", "usr", "USR", "" };
const char *hdrStructTp[] = {
"seq", "SEQ", "vlir", "VLIR", "" };
const char *hdrModes[] = {
"any", "40only", "80only", "c64only", "" };
@ -62,9 +66,10 @@ const unsigned char icon1[] = {
char *progName;
char *outputCName=NULL, *outputSName=NULL;
FILE *outputCFile, *outputSFile;
int CFnum=0, SFnum=0;
char *outputCName=NULL, *outputSName=NULL, *outputVName=NULL;
FILE *outputCFile, *outputSFile, *outputVFile;
int CFnum=0, SFnum=0, VFnum=0;
int forceFlag=0;
char outputCMode[2]="w";
char outputSMode[2]="w";
char outputVMode[2]="w";