new option -o
[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   int i;
191
192   /* first we need to create the <filename>.lnk file */
193   sprintf (scratchFileName, "%s.lnk", dstFileName);
194   if (!(lnkfile = fopen (scratchFileName, "w")))
195     {
196       werror (E_FILE_OPEN_ERR, scratchFileName);
197       exit (1);
198     }
199
200   fprintf (lnkfile, "[Objects]\n");
201
202   fprintf (lnkfile, "%s.o\n", dstFileName);
203
204   for (i = 0; i < nrelFiles; i++)
205     fprintf (lnkfile, "%s\n", relFiles[i]);
206
207   fprintf (lnkfile, "\n[Libraries]\n");
208   /* additional libraries if any */
209   for (i = 0; i < nlibFiles; i++)
210     fprintf (lnkfile, "%s\n", libFiles[i]);
211
212
213   fprintf (lnkfile, "\n[Output]\n" "%s.gb", dstFileName);
214
215   fclose (lnkfile);
216
217   buildCmdLine (buffer,port->linker.cmd, dstFileName, NULL, NULL, NULL);
218   /* call the linker */
219   if (my_system (buffer))
220     {
221       perror ("Cannot exec linker");
222       exit (1);
223     }
224 }
225
226 static bool
227 _parseOptions (int *pargc, char **argv, int *i)
228 {
229   if (argv[*i][0] == '-')
230     {
231       if (argv[*i][1] == 'b' && IS_GB)
232         {
233           int bank = atoi (argv[*i] + 3);
234           char buffer[128];
235           switch (argv[*i][2])
236             {
237             case 'o':
238               /* ROM bank */
239               sprintf (buffer, "CODE_%u", bank);
240               gbz80_port.mem.code_name = Safe_strdup (buffer);
241               return TRUE;
242             case 'a':
243               /* RAM bank */
244               sprintf (buffer, "DATA_%u", bank);
245               gbz80_port.mem.data_name = Safe_strdup (buffer);
246               return TRUE;
247             }
248         }
249       else if (!strncmp (argv[*i], "--asm=", 6))
250         {
251           if (!strcmp (argv[*i], "--asm=rgbds"))
252             {
253               asm_addTree (&_rgbds_gb);
254               gbz80_port.assembler.cmd = _gbz80_rgbasmCmd;
255               gbz80_port.linker.cmd = _gbz80_rgblinkCmd;
256               gbz80_port.linker.do_link = _gbz80_rgblink;
257               _G.asmType = ASM_TYPE_RGBDS;
258               return TRUE;
259             }
260           else if (!strcmp (argv[*i], "--asm=asxxxx"))
261             {
262               _G.asmType = ASM_TYPE_ASXXXX;
263               return TRUE;
264             }
265           else if (!strcmp (argv[*i], "--asm=isas"))
266             {
267               asm_addTree (&_isas_gb);
268               /* Munge the function prefix */
269               gbz80_port.fun_prefix = "";
270               _G.asmType = ASM_TYPE_ISAS;
271               return TRUE;
272             }
273           else if (!strcmp (argv[*i], "--asm=z80asm"))
274             {
275               port->assembler.externGlobal = TRUE;
276               asm_addTree (&_z80asm_z80);
277               _G.asmType = ASM_TYPE_ISAS;
278               return TRUE;
279             }
280         }
281     }
282   return FALSE;
283 }
284
285 static void
286 _setValues(void)
287 {
288   if (options.nostdlib == FALSE)
289     {
290       setMainValue ("z80libspec", "-k{libdir}{sep}{port} -l{port}.lib");
291       setMainValue ("z80crt0", "{libdir}{sep}{port}{sep}crt0{objext}");
292     }
293   else
294     {
295       setMainValue ("z80libspec", "");
296       setMainValue ("z80crt0", "");
297     }
298
299   setMainValue ("z80extralibfiles", joinn (libFiles, nlibFiles));
300   setMainValue ("z80extralibpaths", joinn (libPaths, nlibPaths));
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 ("z80stdobjdstfilename" , "{dstfilename}{objext}");
314   setMainValue ("z80stdlinkdstfilename", "{dstfilename}{z80outext}");
315
316   setMainValue ("z80extraobj", joinn (relFiles, nrelFiles));
317   
318   sprintf (buffer, "-b_CODE=0x%04X -b_DATA=0x%04X", options.code_loc, options.data_loc);
319   setMainValue ("z80bases", buffer);
320 }
321
322 static void
323 _finaliseOptions (void)
324 {
325   port->mem.default_local_map = data;
326   port->mem.default_globl_map = data;
327   if (_G.asmType == ASM_TYPE_ASXXXX && IS_GB)
328     asm_addTree (&_asxxxx_gb);
329
330   _setValues();
331 }
332
333 static void
334 _setDefaultOptions (void)
335 {
336   options.genericPtr = 1;       /* default on */
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     "{bindir}{sep}link-{port} -n -c -- {z80bases} -m -j" \
445     " {z80libspec}" \
446     " {z80extralibfiles} {z80extralibpaths}" \
447     " {z80outputtypeflag} {z80linkdstfilename}" \
448     " {z80crt0}" \
449     " {dstfilename}{objext}" \
450     " {z80extraobj}" 
451
452 #define ASMCMD \
453     "{bindir}{sep}as-{port} -plosgff {z80objdstfilename} {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 };