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