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