* src/z80/ralloc.c (packRegsForHLUse): Banned IFXs from being packed into HL.
[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.float_rent = 1;
324   options.noRegParams = 1;
325   /* Default code and data locations. */
326   options.code_loc = 0x200;
327
328   if (IS_GB) 
329     {
330       options.data_loc = 0xC000;
331     }
332   else
333     {
334       options.data_loc = 0x8000;
335     }
336
337   optimize.global_cse = 1;
338   optimize.label1 = 1;
339   optimize.label2 = 1;
340   optimize.label3 = 1;
341   optimize.label4 = 1;
342   optimize.loopInvariant = 1;
343   optimize.loopInduction = 1;
344 }
345
346 /* Mangaling format:
347     _fun_policy_params
348     where:
349       policy is the function policy
350       params is the parameter format
351
352    policy format:
353     rsp
354     where:
355       r is 'r' for reentrant, 's' for static functions
356       s is 'c' for callee saves, 'r' for caller saves
357       p is 'p' for profiling on, 'x' for profiling off
358     examples:
359       rr - reentrant, caller saves
360    params format:
361     A combination of register short names and s to signify stack variables.
362     examples:
363       bds - first two args appear in BC and DE, the rest on the stack
364       s - all arguments are on the stack.
365 */
366 static char *
367 _mangleSupportFunctionName(char *original)
368 {
369   char buffer[128];
370
371   sprintf(buffer, "%s_rr%s_%s", original,
372           options.profile ? "f" : "x",
373           options.noRegParams ? "s" : "bds"
374           );
375
376   return Safe_strdup(buffer);
377 }
378
379 static const char *
380 _getRegName (struct regs *reg)
381 {
382   if (reg)
383     {
384       return reg->name;
385     }
386   assert (0);
387   return "err";
388 }
389
390 static bool
391 _hasNativeMulFor (iCode *ic, sym_link *left, sym_link *right)
392 {
393   sym_link *test = NULL;
394   value *val;
395
396   if ( ic->op != '*')
397     {
398       return FALSE;
399     }
400
401   if ( IS_LITERAL (left))
402     {
403       test = left;
404       val = OP_VALUE (IC_LEFT (ic));
405     }
406   else if ( IS_LITERAL (right))
407     {
408       test = left;
409       val = OP_VALUE (IC_RIGHT (ic));
410     }
411   else
412     {
413       return FALSE;
414     }
415
416   if ( getSize (test) <= 2)
417     {
418       return TRUE;
419     }
420
421   return FALSE;
422 }
423
424 #define LINKCMD \
425     "{bindir}{sep}link-{port} -n -c -- {z80bases} -m -j" \
426     " {z80libspec}" \
427     " {z80extralibfiles} {z80extralibpaths}" \
428     " {z80outputtypeflag} {srcfilename}{z80outext}" \
429     " {z80crt0}" \
430     " {srcfilename}{objext}" \
431     " {z80extraobj}" 
432
433 #define ASMCMD \
434     "{bindir}{sep}as-{port} -plosgff {srcfilename}{objext} {srcfilename}{asmext}"
435
436 /* Globals */
437 PORT z80_port =
438 {
439   TARGET_ID_Z80,
440   "z80",
441   "Zilog Z80",                  /* Target name */
442   {
443     FALSE,
444     MODEL_MEDIUM | MODEL_SMALL,
445     MODEL_SMALL
446   },
447   {
448     NULL,
449     ASMCMD,
450     "-plosgff",                 /* Options with debug */
451     "-plosgff",                 /* Options without debug */
452     0,
453     ".asm"
454   },
455   {
456     NULL,
457     LINKCMD,
458     NULL,
459     ".o"
460   },
461   {
462     _z80_defaultRules
463   },
464   {
465         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
466     1, 2, 2, 4, 2, 2, 2, 1, 4, 4
467   },
468   {
469     "XSEG",
470     "STACK",
471     "CODE",
472     "DATA",
473     "ISEG",
474     "XSEG",
475     "BSEG",
476     "RSEG",
477     "GSINIT",
478     "OVERLAY",
479     "GSFINAL",
480     "HOME",
481     NULL,
482     NULL,
483     1
484   },
485   {
486     -1, 0, 0, 4, 0, 2
487   },
488     /* Z80 has no native mul/div commands */
489   {
490     0, 2
491   },
492   "_",
493   _z80_init,
494   _parseOptions,
495   _finaliseOptions,
496   _setDefaultOptions,
497   z80_assignRegisters,
498   _getRegName,
499   _keywords,
500   0,                            /* no assembler preamble */
501   0,                            /* no local IVT generation code */
502   _reset_regparm,
503   _reg_parm,
504   _process_pragma,
505   _mangleSupportFunctionName,
506   _hasNativeMulFor,
507   TRUE,
508   0,                            /* leave lt */
509   0,                            /* leave gt */
510   1,                            /* transform <= to ! > */
511   1,                            /* transform >= to ! < */
512   1,                            /* transform != to !(a == b) */
513   0,                            /* leave == */
514   TRUE,                         /* Array initializer support. */        
515   PORT_MAGIC
516 };
517
518 /* Globals */
519 PORT gbz80_port =
520 {
521   TARGET_ID_GBZ80,
522   "gbz80",
523   "Gameboy Z80-like",           /* Target name */
524   {
525     FALSE,
526     MODEL_MEDIUM | MODEL_SMALL,
527     MODEL_SMALL
528   },
529   {
530     NULL,
531     ASMCMD,
532     "-plosgff",                 /* Options with debug */
533     "-plosgff",                 /* Options without debug */
534     0,
535     ".asm"
536   },
537   {
538     NULL,
539     LINKCMD,
540     NULL,
541     ".o"
542   },
543   {
544     _gbz80_defaultRules
545   },
546   {
547     /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
548     1, 2, 2, 4, 2, 2, 2, 1, 4, 4
549   },
550   {
551     "XSEG",
552     "STACK",
553     "CODE",
554     "DATA",
555     "ISEG",
556     "XSEG",
557     "BSEG",
558     "RSEG",
559     "GSINIT",
560     "OVERLAY",
561     "GSFINAL",
562     "HOME",
563     NULL,
564     NULL,
565     1
566   },
567   {
568     -1, 0, 0, 2, 0, 4
569   },
570     /* gbZ80 has no native mul/div commands */
571   {
572     0, 2
573   },
574   "_",
575   _gbz80_init,
576   _parseOptions,
577   _finaliseOptions,
578   _setDefaultOptions,
579   z80_assignRegisters,
580   _getRegName,
581   _keywords,
582   0,                            /* no assembler preamble */
583   0,                            /* no local IVT generation code */
584   _reset_regparm,
585   _reg_parm,
586   _process_pragma,
587   _mangleSupportFunctionName,
588   _hasNativeMulFor,
589   TRUE,
590   0,                            /* leave lt */
591   0,                            /* leave gt */
592   1,                            /* transform <= to ! > */
593   1,                            /* transform >= to ! < */
594   1,                            /* transform != to !(a == b) */
595   0,                            /* leave == */
596   TRUE,                         /* Array initializer support. */
597   PORT_MAGIC
598 };