* support/Util/NewAlloc.c (freeTrace): Changed free for the gc case to not free...
[fw/sdcc] / src / z80 / main.c
1 /*-------------------------------------------------------------------------
2   main.c - Z80 specific definitions.
3
4   Michael Hope <michaelh@juju.net.nz> 2001
5
6    This program is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by the
8    Free Software Foundation; either version 2, or (at your option) any
9    later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20    In other words, you are welcome to use, share and improve this program.
21    You are forbidden to forbid anyone else to use, share and improve
22    what you give them.   Help stamp out software-hoarding!
23 -------------------------------------------------------------------------*/
24
25 #include "z80.h"
26 #include "MySystem.h"
27 #include "BuildCmd.h"
28 #include "SDCCutil.h"
29
30 static char _z80_defaultRules[] =
31 {
32 #include "peeph.rul"
33 #include "peeph-z80.rul"
34 };
35
36 static char _gbz80_defaultRules[] =
37 {
38 #include "peeph.rul"
39 #include "peeph-gbz80.rul"
40 };
41
42 Z80_OPTS z80_opts;
43
44 typedef enum
45   {
46     /* Must be first */
47     ASM_TYPE_ASXXXX,
48     ASM_TYPE_RGBDS,
49     ASM_TYPE_ISAS
50   }
51 ASM_TYPE;
52
53 static struct
54   {
55     ASM_TYPE asmType;
56     /* determine if we can register a parameter */    
57     int regParams;
58   }
59 _G;
60
61 static char *_keywords[] =
62 {
63   "sfr",
64   "nonbanked",
65   "banked",
66   NULL
67 };
68
69 extern PORT gbz80_port;
70 extern PORT z80_port;
71
72 #include "mappings.i"
73
74 static void
75 _z80_init (void)
76 {
77   z80_opts.sub = SUB_Z80;
78   asm_addTree (&_asxxxx_z80);
79 }
80
81 static void
82 _gbz80_init (void)
83 {
84   z80_opts.sub = SUB_GBZ80;
85 }
86
87 static void
88 _reset_regparm ()
89 {
90   _G.regParams = 0;
91 }
92
93 static int
94 _reg_parm (sym_link * l)
95 {
96   if (options.noRegParams) 
97     {
98       return FALSE;
99     }
100   else 
101     {
102       if (_G.regParams == 2)
103         {
104           return FALSE;
105         }
106       else
107         {
108           _G.regParams++;
109           return TRUE;
110         }
111     }
112 }
113
114 static int
115 _process_pragma (const char *sz)
116 {
117   if (startsWith (sz, "bank="))
118     {
119       char buffer[128];
120       strcpy (buffer, sz + 5);
121       chomp (buffer);
122       if (isdigit (buffer[0]))
123         {
124
125         }
126       else if (!strcmp (buffer, "BASE"))
127         {
128           strcpy (buffer, "HOME");
129         }
130       if (isdigit (buffer[0]))
131         {
132           /* Arg was a bank number.  Handle in an ASM independent
133              way. */
134           char num[128];
135           strcpy (num, sz + 5);
136           chomp (num);
137
138           switch (_G.asmType)
139             {
140             case ASM_TYPE_ASXXXX:
141               sprintf (buffer, "CODE_%s", num);
142               break;
143             case ASM_TYPE_RGBDS:
144               sprintf (buffer, "CODE,BANK[%s]", num);
145               break;
146             case ASM_TYPE_ISAS:
147               /* PENDING: what to use for ISAS? */
148               sprintf (buffer, "CODE,BANK(%s)", num);
149               break;
150             default:
151               wassert (0);
152             }
153         }
154       gbz80_port.mem.code_name = Safe_strdup (buffer);
155       code->sname = gbz80_port.mem.code_name;
156       return 0;
157     }
158   return 1;
159 }
160
161 static const char *_gbz80_rgbasmCmd[] =
162 {
163   "rgbasm", "-o$1.o", "$1.asm", NULL
164 };
165
166 static const char *_gbz80_rgblinkCmd[] =
167 {
168   "xlink", "-tg", "-n$1.sym", "-m$1.map", "-zFF", "$1.lnk", NULL
169 };
170
171 static void
172 _gbz80_rgblink (void)
173 {
174   FILE *lnkfile;
175   const char *sz;
176
177   int i;
178   sz = srcFileName;
179   if (!sz)
180     sz = "a";
181
182   /* first we need to create the <filename>.lnk file */
183   sprintf (scratchFileName, "%s.lnk", sz);
184   if (!(lnkfile = fopen (scratchFileName, "w")))
185     {
186       werror (E_FILE_OPEN_ERR, scratchFileName);
187       exit (1);
188     }
189
190   fprintf (lnkfile, "[Objects]\n");
191
192   if (srcFileName)
193     fprintf (lnkfile, "%s.o\n", sz);
194
195   for (i = 0; i < nrelFiles; i++)
196     fprintf (lnkfile, "%s\n", relFiles[i]);
197
198   fprintf (lnkfile, "\n[Libraries]\n");
199   /* additional libraries if any */
200   for (i = 0; i < nlibFiles; i++)
201     fprintf (lnkfile, "%s\n", libFiles[i]);
202
203
204   fprintf (lnkfile, "\n[Output]\n" "%s.gb", sz);
205
206   fclose (lnkfile);
207
208   buildCmdLine (buffer,port->linker.cmd, sz, NULL, NULL, NULL);
209   /* call the linker */
210   if (my_system (buffer))
211     {
212       perror ("Cannot exec linker");
213       exit (1);
214     }
215 }
216
217 static bool
218 _parseOptions (int *pargc, char **argv, int *i)
219 {
220   if (argv[*i][0] == '-')
221     {
222       if (argv[*i][1] == 'b' && IS_GB)
223         {
224           int bank = atoi (argv[*i] + 3);
225           char buffer[128];
226           switch (argv[*i][2])
227             {
228             case 'o':
229               /* ROM bank */
230               sprintf (buffer, "CODE_%u", bank);
231               gbz80_port.mem.code_name = Safe_strdup (buffer);
232               return TRUE;
233             case 'a':
234               /* RAM bank */
235               sprintf (buffer, "DATA_%u", bank);
236               gbz80_port.mem.data_name = Safe_strdup (buffer);
237               return TRUE;
238             }
239         }
240       else if (!strncmp (argv[*i], "--asm=", 6))
241         {
242           if (!strcmp (argv[*i], "--asm=rgbds"))
243             {
244               asm_addTree (&_rgbds_gb);
245               gbz80_port.assembler.cmd = _gbz80_rgbasmCmd;
246               gbz80_port.linker.cmd = _gbz80_rgblinkCmd;
247               gbz80_port.linker.do_link = _gbz80_rgblink;
248               _G.asmType = ASM_TYPE_RGBDS;
249               return TRUE;
250             }
251           else if (!strcmp (argv[*i], "--asm=asxxxx"))
252             {
253               _G.asmType = ASM_TYPE_ASXXXX;
254               return TRUE;
255             }
256           else if (!strcmp (argv[*i], "--asm=isas"))
257             {
258               asm_addTree (&_isas_gb);
259               /* Munge the function prefix */
260               gbz80_port.fun_prefix = "";
261               _G.asmType = ASM_TYPE_ISAS;
262               return TRUE;
263             }
264         }
265     }
266   return FALSE;
267 }
268
269 static void
270 _setValues(void)
271 {
272   if (options.nostdlib == FALSE)
273     {
274       setMainValue ("z80libspec", "-k{libdir}{sep}{port} -l{port}.lib");
275       setMainValue ("z80crt0", "{libdir}{sep}{port}{sep}crt0{objext}");
276     }
277   else
278     {
279       setMainValue ("z80libspec", "");
280       setMainValue ("z80crt0", "");
281     }
282
283   setMainValue ("z80extralibfiles", joinn (libFiles, nlibFiles));
284   setMainValue ("z80extralibpaths", joinn (libPaths, nlibPaths));
285
286   if (IS_GB)
287     {
288       setMainValue ("z80outputtypeflag", "-z");
289       setMainValue ("z80outext", ".gb");
290     }
291   else
292     {
293       setMainValue ("z80outputtypeflag", "-i");
294       setMainValue ("z80outext", ".ihx");
295     }
296
297   setMainValue ("z80extraobj", joinn (relFiles, nrelFiles));
298   
299   sprintf (buffer, "-b_CODE=0x%04X -b_DATA=0x%04X", options.code_loc, options.data_loc);
300   setMainValue ("z80bases", buffer);
301 }
302
303 static void
304 _finaliseOptions (void)
305 {
306   port->mem.default_local_map = data;
307   port->mem.default_globl_map = data;
308   if (_G.asmType == ASM_TYPE_ASXXXX && IS_GB)
309     asm_addTree (&_asxxxx_gb);
310
311   _setValues();
312 }
313
314 static void
315 _setDefaultOptions (void)
316 {
317   options.genericPtr = 1;       /* default on */
318   options.nopeep = 0;
319   options.stackAuto = 1;
320   options.mainreturn = 1;
321   /* first the options part */
322   options.intlong_rent = 1;
323   options.noRegParams = 1;
324   /* Default code and data locations. */
325   options.code_loc = 0x200;
326
327   if (IS_GB) 
328     {
329       options.data_loc = 0xC000;
330     }
331   else
332     {
333       options.data_loc = 0x8000;
334     }
335
336   optimize.global_cse = 1;
337   optimize.label1 = 1;
338   optimize.label2 = 1;
339   optimize.label3 = 1;
340   optimize.label4 = 1;
341   optimize.loopInvariant = 1;
342   optimize.loopInduction = 1;
343 }
344
345 /* Mangaling format:
346     _fun_policy_params
347     where:
348       policy is the function policy
349       params is the parameter format
350
351    policy format:
352     rsp
353     where:
354       r is 'r' for reentrant, 's' for static functions
355       s is 'c' for callee saves, 'r' for caller saves
356       p is 'p' for profiling on, 'x' for profiling off
357     examples:
358       rr - reentrant, caller saves
359    params format:
360     A combination of register short names and s to signify stack variables.
361     examples:
362       bds - first two args appear in BC and DE, the rest on the stack
363       s - all arguments are on the stack.
364 */
365 static char *
366 _mangleSupportFunctionName(char *original)
367 {
368   char buffer[128];
369
370   sprintf(buffer, "%s_rr%s_%s", original,
371           options.profile ? "f" : "x",
372           options.noRegParams ? "s" : "bds"
373           );
374
375   return Safe_strdup(buffer);
376 }
377
378 static const char *
379 _getRegName (struct regs *reg)
380 {
381   if (reg)
382     {
383       return reg->name;
384     }
385   assert (0);
386   return "err";
387 }
388
389 #define LINKCMD \
390     "{bindir}{sep}link-{port} -n -c -- {z80bases} -m -j" \
391     " {z80libspec}" \
392     " {z80extralibfiles} {z80extralibpaths}" \
393     " {z80outputtypeflag} {srcfilename}{z80outext}" \
394     " {z80crt0}" \
395     " {srcfilename}{objext}" \
396     " {z80extraobj}" 
397
398 #define ASMCMD \
399     "{bindir}{sep}as-{port} -plosgff {srcfilename}{objext} {srcfilename}{asmext}"
400
401 /* Globals */
402 PORT z80_port =
403 {
404   TARGET_ID_Z80,
405   "z80",
406   "Zilog Z80",                  /* Target name */
407   {
408     FALSE,
409     MODEL_MEDIUM | MODEL_SMALL,
410     MODEL_SMALL
411   },
412   {
413     NULL,
414     ASMCMD,
415     "-plosgff",                 /* Options with debug */
416     "-plosgff",                 /* Options without debug */
417     0,
418     ".asm"
419   },
420   {
421     NULL,
422     LINKCMD,
423     NULL,
424     ".o"
425   },
426   {
427     _z80_defaultRules
428   },
429   {
430         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
431     1, 2, 2, 4, 2, 2, 2, 1, 4, 4
432   },
433   {
434     "XSEG",
435     "STACK",
436     "CODE",
437     "DATA",
438     "ISEG",
439     "XSEG",
440     "BSEG",
441     "RSEG",
442     "GSINIT",
443     "OVERLAY",
444     "GSFINAL",
445     "HOME",
446     NULL,
447     NULL,
448     1
449   },
450   {
451     -1, 0, 0, 4, 0, 2
452   },
453     /* Z80 has no native mul/div commands */
454   {
455     0, 2
456   },
457   "_",
458   _z80_init,
459   _parseOptions,
460   _finaliseOptions,
461   _setDefaultOptions,
462   z80_assignRegisters,
463   _getRegName,
464   _keywords,
465   0,                            /* no assembler preamble */
466   0,                            /* no local IVT generation code */
467   _reset_regparm,
468   _reg_parm,
469   _process_pragma,
470   _mangleSupportFunctionName,
471   TRUE,
472   0,                            /* leave lt */
473   0,                            /* leave gt */
474   1,                            /* transform <= to ! > */
475   1,                            /* transform >= to ! < */
476   1,                            /* transform != to !(a == b) */
477   0,                            /* leave == */
478   TRUE,                         /* Array initializer support. */        
479   PORT_MAGIC
480 };
481
482 /* Globals */
483 PORT gbz80_port =
484 {
485   TARGET_ID_GBZ80,
486   "gbz80",
487   "Gameboy Z80-like",           /* Target name */
488   {
489     FALSE,
490     MODEL_MEDIUM | MODEL_SMALL,
491     MODEL_SMALL
492   },
493   {
494     NULL,
495     ASMCMD,
496     "-plosgff",                 /* Options with debug */
497     "-plosgff",                 /* Options without debug */
498     0,
499     ".asm"
500   },
501   {
502     NULL,
503     LINKCMD,
504     NULL,
505     ".o"
506   },
507   {
508     _gbz80_defaultRules
509   },
510   {
511     /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
512     1, 2, 2, 4, 2, 2, 2, 1, 4, 4
513   },
514   {
515     "XSEG",
516     "STACK",
517     "CODE",
518     "DATA",
519     "ISEG",
520     "XSEG",
521     "BSEG",
522     "RSEG",
523     "GSINIT",
524     "OVERLAY",
525     "GSFINAL",
526     "HOME",
527     NULL,
528     NULL,
529     1
530   },
531   {
532     -1, 0, 0, 2, 0, 4
533   },
534     /* gbZ80 has no native mul/div commands */
535   {
536     0, 2
537   },
538   "_",
539   _gbz80_init,
540   _parseOptions,
541   _finaliseOptions,
542   _setDefaultOptions,
543   z80_assignRegisters,
544   _getRegName,
545   _keywords,
546   0,                            /* no assembler preamble */
547   0,                            /* no local IVT generation code */
548   _reset_regparm,
549   _reg_parm,
550   _process_pragma,
551   _mangleSupportFunctionName,
552   TRUE,
553   0,                            /* leave lt */
554   0,                            /* leave gt */
555   1,                            /* transform <= to ! > */
556   1,                            /* transform >= to ! < */
557   1,                            /* transform != to !(a == b) */
558   0,                            /* leave == */
559   FALSE,                        /* No array initializer support. */
560   PORT_MAGIC
561 };