fixed width array of pointers replaced with sets;
[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 static OPTION _z80_options[] = 
45   {
46     { 0,   "--callee-saves-bc", &z80_opts.calleeSavesBC, "Force a called function to always save BC" },
47     { 0, NULL }
48   };
49
50 typedef enum
51   {
52     /* Must be first */
53     ASM_TYPE_ASXXXX,
54     ASM_TYPE_RGBDS,
55     ASM_TYPE_ISAS,
56     ASM_TYPE_Z80ASM
57   }
58 ASM_TYPE;
59
60 static struct
61   {
62     ASM_TYPE asmType;
63     /* determine if we can register a parameter */    
64     int regParams;
65   }
66 _G;
67
68 static char *_keywords[] =
69 {
70   "sfr",
71   "nonbanked",
72   "banked",
73   NULL
74 };
75
76 extern PORT gbz80_port;
77 extern PORT z80_port;
78
79 #include "mappings.i"
80
81 static builtins _z80_builtins[] = {
82   /* Disabled for now.
83     { "__builtin_strcpy", "v", 2, {"cg*", "cg*" } },
84     { "__builtin_memcpy", "cg*", 3, {"cg*", "cg*", "ui" } },
85   */
86     { NULL , NULL,0, {NULL}}
87 };    
88
89 static void
90 _z80_init (void)
91 {
92   z80_opts.sub = SUB_Z80;
93   asm_addTree (&_asxxxx_z80);
94 }
95
96 static void
97 _gbz80_init (void)
98 {
99   z80_opts.sub = SUB_GBZ80;
100 }
101
102 static void
103 _reset_regparm ()
104 {
105   _G.regParams = 0;
106 }
107
108 static int
109 _reg_parm (sym_link * l)
110 {
111   if (options.noRegParams) 
112     {
113       return FALSE;
114     }
115   else 
116     {
117       if (_G.regParams == 2)
118         {
119           return FALSE;
120         }
121       else
122         {
123           _G.regParams++;
124           return TRUE;
125         }
126     }
127 }
128
129 static int
130 _process_pragma (const char *sz)
131 {
132   if (startsWith (sz, "bank="))
133     {
134       char buffer[128];
135       strcpy (buffer, sz + 5);
136       chomp (buffer);
137       if (isdigit (buffer[0]))
138         {
139
140         }
141       else if (!strcmp (buffer, "BASE"))
142         {
143           strcpy (buffer, "HOME");
144         }
145       if (isdigit (buffer[0]))
146         {
147           /* Arg was a bank number.  Handle in an ASM independent
148              way. */
149           char num[128];
150           strcpy (num, sz + 5);
151           chomp (num);
152
153           switch (_G.asmType)
154             {
155             case ASM_TYPE_ASXXXX:
156               sprintf (buffer, "CODE_%s", num);
157               break;
158             case ASM_TYPE_RGBDS:
159               sprintf (buffer, "CODE,BANK[%s]", num);
160               break;
161             case ASM_TYPE_ISAS:
162               /* PENDING: what to use for ISAS? */
163               sprintf (buffer, "CODE,BANK(%s)", num);
164               break;
165             default:
166               wassert (0);
167             }
168         }
169       gbz80_port.mem.code_name = Safe_strdup (buffer);
170       code->sname = gbz80_port.mem.code_name;
171       return 0;
172     }
173   return 1;
174 }
175
176 static const char *_gbz80_rgbasmCmd[] =
177 {
178   "rgbasm", "-o\"$1.o\"", "\"$1.asm\"", NULL
179 };
180
181 static const char *_gbz80_rgblinkCmd[] =
182 {
183   "xlink", "-tg", "-n\"$1.sym\"", "-m\"$1.map\"", "-zFF", "\"$1.lnk\"", NULL
184 };
185
186 static void
187 _gbz80_rgblink (void)
188 {
189   FILE *lnkfile;
190
191   /* first we need to create the <filename>.lnk file */
192   sprintf (scratchFileName, "%s.lnk", dstFileName);
193   if (!(lnkfile = fopen (scratchFileName, "w")))
194     {
195       werror (E_FILE_OPEN_ERR, scratchFileName);
196       exit (1);
197     }
198
199   fprintf (lnkfile, "[Objects]\n");
200
201   fprintf (lnkfile, "%s.o\n", dstFileName);
202
203   fputStrSet(lnkfile, relFilesSet);
204
205   fprintf (lnkfile, "\n[Libraries]\n");
206   /* additional libraries if any */
207   fputStrSet(lnkfile, libFilesSet);
208
209   fprintf (lnkfile, "\n[Output]\n" "%s.gb", dstFileName);
210
211   fclose (lnkfile);
212
213   buildCmdLine (buffer,port->linker.cmd, dstFileName, NULL, NULL, NULL);
214   /* call the linker */
215   if (my_system (buffer))
216     {
217       perror ("Cannot exec linker");
218       exit (1);
219     }
220 }
221
222 static bool
223 _parseOptions (int *pargc, char **argv, int *i)
224 {
225   if (argv[*i][0] == '-')
226     {
227       if (argv[*i][1] == 'b' && IS_GB)
228         {
229           int bank = atoi (argv[*i] + 3);
230           char buffer[128];
231           switch (argv[*i][2])
232             {
233             case 'o':
234               /* ROM bank */
235               sprintf (buffer, "CODE_%u", bank);
236               gbz80_port.mem.code_name = Safe_strdup (buffer);
237               return TRUE;
238             case 'a':
239               /* RAM bank */
240               sprintf (buffer, "DATA_%u", bank);
241               gbz80_port.mem.data_name = Safe_strdup (buffer);
242               return TRUE;
243             }
244         }
245       else if (!strncmp (argv[*i], "--asm=", 6))
246         {
247           if (!strcmp (argv[*i], "--asm=rgbds"))
248             {
249               asm_addTree (&_rgbds_gb);
250               gbz80_port.assembler.cmd = _gbz80_rgbasmCmd;
251               gbz80_port.linker.cmd = _gbz80_rgblinkCmd;
252               gbz80_port.linker.do_link = _gbz80_rgblink;
253               _G.asmType = ASM_TYPE_RGBDS;
254               return TRUE;
255             }
256           else if (!strcmp (argv[*i], "--asm=asxxxx"))
257             {
258               _G.asmType = ASM_TYPE_ASXXXX;
259               return TRUE;
260             }
261           else if (!strcmp (argv[*i], "--asm=isas"))
262             {
263               asm_addTree (&_isas_gb);
264               /* Munge the function prefix */
265               gbz80_port.fun_prefix = "";
266               _G.asmType = ASM_TYPE_ISAS;
267               return TRUE;
268             }
269           else if (!strcmp (argv[*i], "--asm=z80asm"))
270             {
271               port->assembler.externGlobal = TRUE;
272               asm_addTree (&_z80asm_z80);
273               _G.asmType = ASM_TYPE_ISAS;
274               return TRUE;
275             }
276         }
277     }
278   return FALSE;
279 }
280
281 static void
282 _setValues(void)
283 {
284   const char *s;
285
286   if (options.nostdlib == FALSE)
287     {
288       setMainValue ("z80libspec", "-l\"{port}.lib\"");
289       setMainValue ("z80crt0", "\"crt0{objext}\"");
290     }
291   else
292     {
293       setMainValue ("z80libspec", "");
294       setMainValue ("z80crt0", "");
295     }
296
297   setMainValue ("z80extralibfiles", (s = joinStrSet(libFilesSet)));
298   Safe_free((void *)s);
299   setMainValue ("z80extralibpaths", (s = joinStrSet(libPathsSet)));
300   Safe_free((void *)s);
301
302   if (IS_GB)
303     {
304       setMainValue ("z80outputtypeflag", "-z");
305       setMainValue ("z80outext", ".gb");
306     }
307   else
308     {
309       setMainValue ("z80outputtypeflag", "-i");
310       setMainValue ("z80outext", ".ihx");
311     }
312
313   setMainValue ("stdobjdstfilename" , "{dstfilename}{objext}");
314   setMainValue ("stdlinkdstfilename", "{dstfilename}{z80outext}");
315
316   setMainValue ("z80extraobj", (s = joinStrSet(relFilesSet)));
317   Safe_free((void *)s);
318
319   sprintf (buffer, "-b_CODE=0x%04X -b_DATA=0x%04X", options.code_loc, options.data_loc);
320   setMainValue ("z80bases", buffer);
321 }
322
323 static void
324 _finaliseOptions (void)
325 {
326   port->mem.default_local_map = data;
327   port->mem.default_globl_map = data;
328   if (_G.asmType == ASM_TYPE_ASXXXX && IS_GB)
329     asm_addTree (&_asxxxx_gb);
330
331   _setValues();
332 }
333
334 static void
335 _setDefaultOptions (void)
336 {
337   options.nopeep = 0;
338   options.stackAuto = 1;
339   options.mainreturn = 1;
340   /* first the options part */
341   options.intlong_rent = 1;
342   options.float_rent = 1;
343   options.noRegParams = 1;
344   /* Default code and data locations. */
345   options.code_loc = 0x200;
346
347   if (IS_GB) 
348     {
349       options.data_loc = 0xC000;
350     }
351   else
352     {
353       options.data_loc = 0x8000;
354     }
355
356   optimize.global_cse = 1;
357   optimize.label1 = 1;
358   optimize.label2 = 1;
359   optimize.label3 = 1;
360   optimize.label4 = 1;
361   optimize.loopInvariant = 1;
362   optimize.loopInduction = 1;
363 }
364
365 /* Mangaling format:
366     _fun_policy_params
367     where:
368       policy is the function policy
369       params is the parameter format
370
371    policy format:
372     rsp
373     where:
374       r is 'r' for reentrant, 's' for static functions
375       s is 'c' for callee saves, 'r' for caller saves
376       p is 'p' for profiling on, 'x' for profiling off
377     examples:
378       rr - reentrant, caller saves
379    params format:
380     A combination of register short names and s to signify stack variables.
381     examples:
382       bds - first two args appear in BC and DE, the rest on the stack
383       s - all arguments are on the stack.
384 */
385 static char *
386 _mangleSupportFunctionName(char *original)
387 {
388   char buffer[128];
389
390   sprintf(buffer, "%s_rr%s_%s", original,
391           options.profile ? "f" : "x",
392           options.noRegParams ? "s" : "bds"
393           );
394
395   return Safe_strdup(buffer);
396 }
397
398 static const char *
399 _getRegName (struct regs *reg)
400 {
401   if (reg)
402     {
403       return reg->name;
404     }
405   /*  assert (0); */
406   return "err";
407 }
408
409 static bool
410 _hasNativeMulFor (iCode *ic, sym_link *left, sym_link *right)
411 {
412   sym_link *test = NULL;
413   value *val;
414
415   if ( ic->op != '*')
416     {
417       return FALSE;
418     }
419
420   if ( IS_LITERAL (left))
421     {
422       test = left;
423       val = OP_VALUE (IC_LEFT (ic));
424     }
425   else if ( IS_LITERAL (right))
426     {
427       test = left;
428       val = OP_VALUE (IC_RIGHT (ic));
429     }
430   else
431     {
432       return FALSE;
433     }
434
435   if ( getSize (test) <= 2)
436     {
437       return TRUE;
438     }
439
440   return FALSE;
441 }
442
443 #define LINKCMD \
444     "link-{port} -n -c -- {z80bases} -m -j" \
445     " {z80libspec}" \
446     " {z80extralibfiles} {z80extralibpaths}" \
447     " {z80outputtypeflag} \"{linkdstfilename}\"" \
448     " {z80crt0}" \
449     " \"{dstfilename}{objext}\"" \
450     " {z80extraobj}"
451
452 #define ASMCMD \
453     "as-{port} -plosgff \"{objdstfilename}\" \"{dstfilename}{asmext}\""
454
455 /* Globals */
456 PORT z80_port =
457 {
458   TARGET_ID_Z80,
459   "z80",
460   "Zilog Z80",                  /* Target name */
461   NULL,                         /* Processor name */
462   {
463     FALSE,
464     MODEL_MEDIUM | MODEL_SMALL,
465     MODEL_SMALL
466   },
467   {
468     NULL,
469     ASMCMD,
470     "-plosgff",                 /* Options with debug */
471     "-plosgff",                 /* Options without debug */
472     0,
473     ".asm"
474   },
475   {
476     NULL,
477     LINKCMD,
478     NULL,
479     ".o"
480   },
481   {
482     _z80_defaultRules
483   },
484   {
485         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
486     1, 2, 2, 4, 2, 2, 2, 1, 4, 4
487   },
488   {
489     "XSEG",
490     "STACK",
491     "CODE",
492     "DATA",
493     "ISEG",
494     "XSEG",
495     "BSEG",
496     "RSEG",
497     "GSINIT",
498     "OVERLAY",
499     "GSFINAL",
500     "HOME",
501     NULL, /* xidata */
502     NULL, /* xinit */
503     NULL,
504     NULL,
505     1
506   },
507   {
508     -1, 0, 0, 4, 0, 2
509   },
510     /* Z80 has no native mul/div commands */
511   {
512     0, 2
513   },
514   "_",
515   _z80_init,
516   _parseOptions,
517   _z80_options,
518   _finaliseOptions,
519   _setDefaultOptions,
520   z80_assignRegisters,
521   _getRegName,
522   _keywords,
523   0,                            /* no assembler preamble */
524   NULL,                         /* no genAssemblerEnd */
525   0,                            /* no local IVT generation code */
526   0,                            /* no genXINIT code */
527   _reset_regparm,
528   _reg_parm,
529   _process_pragma,
530   _mangleSupportFunctionName,
531   _hasNativeMulFor,
532   TRUE,
533   0,                            /* leave lt */
534   0,                            /* leave gt */
535   1,                            /* transform <= to ! > */
536   1,                            /* transform >= to ! < */
537   1,                            /* transform != to !(a == b) */
538   0,                            /* leave == */
539   TRUE,                         /* Array initializer support. */        
540   0,                            /* no CSE cost estimation yet */
541   _z80_builtins,                /* no builtin functions */
542   GPOINTER,                     /* treat unqualified pointers as "generic" pointers */
543   1,                            /* reset labelKey to 1 */
544   1,                            /* globals & local static allowed */
545   PORT_MAGIC
546 };
547
548 /* Globals */
549 PORT gbz80_port =
550 {
551   TARGET_ID_GBZ80,
552   "gbz80",
553   "Gameboy Z80-like",           /* Target name */
554   NULL,
555   {
556     FALSE,
557     MODEL_MEDIUM | MODEL_SMALL,
558     MODEL_SMALL
559   },
560   {
561     NULL,
562     ASMCMD,
563     "-plosgff",                 /* Options with debug */
564     "-plosgff",                 /* Options without debug */
565     0,
566     ".asm",
567     NULL                        /* no do_assemble function */
568   },
569   {
570     NULL,
571     LINKCMD,
572     NULL,
573     ".o"
574   },
575   {
576     _gbz80_defaultRules
577   },
578   {
579     /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
580     1, 2, 2, 4, 2, 2, 2, 1, 4, 4
581   },
582   {
583     "XSEG",
584     "STACK",
585     "CODE",
586     "DATA",
587     "ISEG",
588     "XSEG",
589     "BSEG",
590     "RSEG",
591     "GSINIT",
592     "OVERLAY",
593     "GSFINAL",
594     "HOME",
595     NULL, /* xidata */
596     NULL, /* xinit */
597     NULL,
598     NULL,
599     1
600   },
601   {
602     -1, 0, 0, 2, 0, 4
603   },
604     /* gbZ80 has no native mul/div commands */
605   {
606     0, 2
607   },
608   "_",
609   _gbz80_init,
610   _parseOptions,
611   _z80_options,
612   _finaliseOptions,
613   _setDefaultOptions,
614   z80_assignRegisters,
615   _getRegName,
616   _keywords,
617   0,                            /* no assembler preamble */
618   NULL,                         /* no genAssemblerEnd */
619   0,                            /* no local IVT generation code */
620   0,                            /* no genXINIT code */
621   _reset_regparm,
622   _reg_parm,
623   _process_pragma,
624   _mangleSupportFunctionName,
625   _hasNativeMulFor,
626   TRUE,
627   0,                            /* leave lt */
628   0,                            /* leave gt */
629   1,                            /* transform <= to ! > */
630   1,                            /* transform >= to ! < */
631   1,                            /* transform != to !(a == b) */
632   0,                            /* leave == */
633   TRUE,                         /* Array initializer support. */
634   0,                            /* no CSE cost estimation yet */
635   NULL,                         /* no builtin functions */
636   GPOINTER,                     /* treat unqualified pointers as "generic" pointers */
637   1,                            /* reset labelKey to 1 */
638   1,                            /* globals & local static allowed */
639   PORT_MAGIC
640 };