Change struct link to struct sym_link to avoid conflict with struct link in unistd.h
[fw/sdcc] / src / z80 / main.c
1 #include "z80.h"
2
3 static char _z80_defaultRules[] =
4 {
5 #include "peeph.rul"
6 #include "peeph-z80.rul"
7 };
8
9 static char _gbz80_defaultRules[] =
10 {
11 #include "peeph.rul"
12 #include "peeph-gbz80.rul"
13 };
14
15 Z80_OPTS z80_opts;
16
17 typedef enum {
18     /* Must be first */
19     ASM_TYPE_ASXXXX,
20     ASM_TYPE_RGBDS,
21     ASM_TYPE_ISAS
22 } ASM_TYPE;
23
24 static struct {
25     ASM_TYPE asmType;
26 } _G;
27
28 static char *_keywords[] = {
29     "sfr",
30     "nonbanked",
31     "banked",
32     NULL 
33 };
34
35 extern PORT gbz80_port;
36 extern PORT z80_port;
37
38 #include "mappings.i"
39
40 static void _z80_init(void)
41 {
42     z80_opts.sub = SUB_Z80;
43     asm_addTree(&_asxxxx_z80);
44 }
45
46 static void _gbz80_init(void)
47 {
48     z80_opts.sub = SUB_GBZ80;
49 }
50
51 static int regParmFlg = 0; /* determine if we can register a parameter */
52
53 static void _reset_regparm()
54 {
55     regParmFlg = 0;
56 }
57
58 static int _reg_parm(sym_link *l)
59 {
60     if (regParmFlg == 2)
61         return 0;
62     
63     regParmFlg++;
64     return 1;
65 }
66
67 static bool _startsWith(const char *sz, const char *key)
68 {
69     return !strncmp(sz, key, strlen(key));
70 }
71
72 static void _chomp(char *sz)
73 {
74     char *nl;
75     while ((nl = strrchr(sz, '\n'))) 
76         *nl = '\0';
77 }
78
79 static int _process_pragma(const char *sz)
80 {
81     if (_startsWith(sz, "bank=")) {
82         char buffer[128];
83         strcpy(buffer, sz+5);
84         _chomp(buffer);
85         if (isdigit(buffer[0])) {
86             
87         }
88         else if (!strcmp(buffer, "BASE")) {
89             strcpy(buffer, "HOME");
90         }
91         if (isdigit(buffer[0])) {
92             /* Arg was a bank number.  Handle in an ASM independent
93                way. */
94             char num[128];
95             strcpy(num, sz+5);
96             _chomp(num);
97
98             switch (_G.asmType) {
99             case ASM_TYPE_ASXXXX:
100                 sprintf(buffer, "CODE_%s", num);
101                 break;
102             case ASM_TYPE_RGBDS:
103                 sprintf(buffer, "CODE,BANK[%s]", num);
104                 break;
105             case ASM_TYPE_ISAS:
106                 /* PENDING: what to use for ISAS? */
107                 sprintf(buffer, "CODE,BANK(%s)", num);
108                 break;
109             default:
110                 wassert(0);
111             }
112         }
113         gbz80_port.mem.code_name = gc_strdup(buffer);
114         code->sname = gbz80_port.mem.code_name;
115         return 0;
116     }
117     return 1;
118 }
119
120 static const char *_gbz80_rgbasmCmd[] = {
121     "rgbasm", "-o$1.o", "$1.asm", NULL
122 };
123
124 static const char *_gbz80_rgblinkCmd[] = {
125     "xlink", "-tg", "-n$1.sym", "-m$1.map", "-zFF", "$1.lnk", NULL
126 };
127
128 static void _gbz80_rgblink(void)
129 {
130     FILE *lnkfile;
131     const char *sz;
132     char *argv[128];
133
134     int i;
135     sz = srcFileName;
136     if (!sz)
137         sz = "a";
138
139     /* first we need to create the <filename>.lnk file */
140     sprintf(buffer,"%s.lnk", sz);
141     if (!(lnkfile = fopen(buffer,"w"))) {
142         werror(E_FILE_OPEN_ERR, buffer);
143         exit(1);
144     }
145
146     fprintf(lnkfile, "[Objects]\n");
147
148     if (srcFileName)
149         fprintf(lnkfile, "%s.o\n", sz);
150
151     for (i = 0 ; i < nrelFiles ; i++ )
152         fprintf (lnkfile,"%s\n",relFiles[i]);
153
154     fprintf(lnkfile, "\n[Libraries]\n");
155     /* additional libraries if any */
156     for (i = 0 ; i < nlibFiles; i++)
157         fprintf (lnkfile,"%s\n",libFiles[i]);
158
159
160     fprintf(lnkfile,"\n[Output]\n" "%s.gb",sz);
161
162     fclose(lnkfile);
163
164     buildCmdLine(buffer, argv, port->linker.cmd, sz, NULL, NULL, NULL);
165     /* call the linker */
166     if (my_system(argv[0], argv)) {
167         perror("Cannot exec linker");
168         exit(1);
169     }
170 }
171
172 static bool _parseOptions(int *pargc, char **argv, int *i)
173 {
174     if (argv[*i][0] == '-') {
175         if (argv[*i][1] == 'b' && IS_GB) {
176             int bank = atoi(argv[*i] + 3);
177             char buffer[128];
178             switch (argv[*i][2]) {
179             case 'o':
180                 /* ROM bank */
181                 sprintf(buffer, "CODE_%u", bank);
182                 gbz80_port.mem.code_name = gc_strdup(buffer);
183                 return TRUE;
184             case 'a':
185                 /* RAM bank */
186                 sprintf(buffer, "DATA_%u", bank);
187                 gbz80_port.mem.data_name = gc_strdup(buffer);
188                 return TRUE;
189             }
190         }
191         else if (!strncmp(argv[*i], "--asm=", 6)) {
192             if (!strcmp(argv[*i], "--asm=rgbds")) {
193                 asm_addTree(&_rgbds_gb);
194                 gbz80_port.assembler.cmd = _gbz80_rgbasmCmd;
195                 gbz80_port.linker.cmd = _gbz80_rgblinkCmd;
196                 gbz80_port.linker.do_link = _gbz80_rgblink;
197                 _G.asmType = ASM_TYPE_RGBDS;
198                 return TRUE;
199             }
200             else if (!strcmp(argv[*i], "--asm=asxxxx")) {
201                 _G.asmType = ASM_TYPE_ASXXXX;
202                 return TRUE;
203             }
204             else if (!strcmp(argv[*i], "--asm=isas")) {
205                 asm_addTree(&_isas_gb);
206                 /* Munge the function prefix */
207                 gbz80_port.fun_prefix = "";
208                 _G.asmType = ASM_TYPE_ISAS;
209                 return TRUE;
210             }
211         }
212     }
213     return FALSE;
214 }
215
216 static void _finaliseOptions(void)
217 {
218     port->mem.default_local_map = data;
219     port->mem.default_globl_map = data;
220     if (_G.asmType == ASM_TYPE_ASXXXX && IS_GB)
221         asm_addTree(&_asxxxx_gb);
222 }
223
224 static void _setDefaultOptions(void)
225 {    
226     options.genericPtr = 1;   /* default on */
227     options.nopeep    = 0;
228     options.stackAuto = 1;
229     options.mainreturn = 1;
230     options.noregparms = 1;
231     options.nodebug = 1;
232     /* first the options part */
233     options.intlong_rent = 1;
234
235     optimize.global_cse = 1;    
236     optimize.label1 = 1;
237     optimize.label2 = 1;
238     optimize.label3 = 1;
239     optimize.label4 = 1;    
240     optimize.loopInvariant = 1;
241     optimize.loopInduction = 0;
242 }
243
244 static const char *_getRegName(struct regs *reg)
245 {
246     if (reg)
247         return reg->name;
248     assert(0);
249     return "err";
250 }
251
252 /** $1 is always the basename.
253     $2 is always the output file.
254     $3 varies
255     $l is the list of extra options that should be there somewhere...
256     MUST be terminated with a NULL.
257 */
258 static const char *_z80_linkCmd[] = {
259     "link-z80", "-nf", "$1", NULL
260 };
261
262 static const char *_z80_asmCmd[] = {
263     "as-z80", "-plosgff", "$1.o", "$1.asm", NULL
264 };
265
266 /** $1 is always the basename.
267     $2 is always the output file.
268     $3 varies
269     $l is the list of extra options that should be there somewhere...
270     MUST be terminated with a NULL.
271 */
272 static const char *_gbz80_linkCmd[] = {
273     "link-gbz80", "-nf", "$1", NULL
274 };
275
276 static const char *_gbz80_asmCmd[] = {
277     "as-gbz80", "-plosgff", "$1.o", "$1.asm", NULL
278 };
279
280 /* Globals */
281 PORT z80_port = {
282     "z80",
283     "Zilog Z80",                /* Target name */
284     {
285         FALSE,
286         MODEL_MEDIUM | MODEL_SMALL,
287         MODEL_SMALL
288     },
289     {   
290         _z80_asmCmd,
291         "-plosgff",             /* Options with debug */
292         "-plosgff",             /* Options without debug */
293     },
294     {
295         _z80_linkCmd,
296         NULL,
297         ".o"
298     },
299     {
300         _z80_defaultRules
301     },
302     {
303         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
304         1, 1, 2, 4, 2, 2, 2, 1, 4, 4
305     },
306     {
307         "XSEG",
308         "STACK",
309         "CODE",
310         "DATA",
311         "ISEG",
312         "XSEG",
313         "BSEG",
314         "RSEG",
315         "GSINIT",
316         "OVERLAY",
317         "GSFINAL",
318         "HOME",
319         NULL,
320         NULL,
321         1
322     },
323     { 
324         -1, 0, 0, 4, 0, 2
325     },
326     /* Z80 has no native mul/div commands */
327     {  
328         0, 2
329     },
330     "_",
331     _z80_init,
332     _parseOptions,
333     _finaliseOptions,
334     _setDefaultOptions,
335     z80_assignRegisters,
336     _getRegName,
337     _keywords,
338     0,  /* no assembler preamble */
339     0,  /* no local IVT generation code */
340     _reset_regparm,
341     _reg_parm,
342     _process_pragma,
343     TRUE
344 };
345
346 /* Globals */
347 PORT gbz80_port = {
348     "gbz80",
349     "Gameboy Z80-like",         /* Target name */
350     {
351         FALSE,
352         MODEL_MEDIUM | MODEL_SMALL,
353         MODEL_SMALL
354     },
355     {   
356         _gbz80_asmCmd,
357         "-plosgff",             /* Options with debug */
358         "-plosgff",             /* Options without debug */
359         1
360     },
361     {
362         _gbz80_linkCmd,
363         NULL,
364         ".o"
365     },
366     {
367         _gbz80_defaultRules
368     },
369     {
370         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
371         1, 1, 2, 4, 2, 2, 2, 1, 4, 4
372     },
373     {
374         "XSEG",
375         "STACK",
376         "CODE",
377         "DATA",
378         "ISEG",
379         "XSEG",
380         "BSEG",
381         "RSEG",
382         "GSINIT",
383         "OVERLAY",
384         "GSFINAL",
385         "HOME",
386         NULL,
387         NULL,
388         1
389     },
390     { 
391         -1, 0, 0, 2, 0, 4
392     },
393     /* gbZ80 has no native mul/div commands */
394     {  
395         0, 2
396     },
397     "_",
398     _gbz80_init,
399     _parseOptions,
400     _finaliseOptions,
401     _setDefaultOptions,
402     z80_assignRegisters,
403     _getRegName,
404     _keywords,
405     0,  /* no assembler preamble */
406     0,  /* no local IVT generation code */
407     _reset_regparm,
408     _reg_parm,
409     _process_pragma,
410     TRUE,
411     0,  /* leave lt */
412     0,  /* leave gt */
413     1,  /* transform <= to ! > */
414     1,  /* transform >= to ! < */
415     1,  /* transform != to !(a == b) */
416     0   /* leave == */
417 };