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