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