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