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