Made linking support base areas and extra libraries. Begin tidy up of gen.c
[fw/sdcc] / src / z80 / main.c
1 #include "z80.h"
2 #include "MySystem.h"
3 #include "BuildCmd.h"
4
5 static char _z80_defaultRules[] =
6 {
7 #include "peeph.rul"
8 #include "peeph-z80.rul"
9 };
10
11 static char _gbz80_defaultRules[] =
12 {
13 #include "peeph.rul"
14 #include "peeph-gbz80.rul"
15 };
16
17 Z80_OPTS z80_opts;
18
19 typedef enum
20   {
21     /* Must be first */
22     ASM_TYPE_ASXXXX,
23     ASM_TYPE_RGBDS,
24     ASM_TYPE_ISAS
25   }
26 ASM_TYPE;
27
28 static struct
29   {
30     ASM_TYPE asmType;
31   }
32 _G;
33
34 static char *_keywords[] =
35 {
36   "sfr",
37   "nonbanked",
38   "banked",
39   NULL
40 };
41
42 extern PORT gbz80_port;
43 extern PORT z80_port;
44
45 #include "mappings.i"
46
47 static void
48 _z80_init (void)
49 {
50   z80_opts.sub = SUB_Z80;
51   asm_addTree (&_asxxxx_z80);
52 }
53
54 static void
55 _gbz80_init (void)
56 {
57   z80_opts.sub = SUB_GBZ80;
58 }
59
60 static int regParmFlg = 0;      /* determine if we can register a parameter */
61
62 static void
63 _reset_regparm ()
64 {
65   regParmFlg = 0;
66 }
67
68 static int
69 _reg_parm (sym_link * l)
70 {
71   if (regParmFlg == 2)
72     return 0;
73
74   regParmFlg++;
75   return 1;
76 }
77
78 static bool
79 _startsWith (const char *sz, const char *key)
80 {
81   return !strncmp (sz, key, strlen (key));
82 }
83
84 static void
85 _chomp (char *sz)
86 {
87   char *nl;
88   while ((nl = strrchr (sz, '\n')))
89     *nl = '\0';
90 }
91
92 static int
93 _process_pragma (const char *sz)
94 {
95   if (_startsWith (sz, "bank="))
96     {
97       char buffer[128];
98       strcpy (buffer, sz + 5);
99       _chomp (buffer);
100       if (isdigit (buffer[0]))
101         {
102
103         }
104       else if (!strcmp (buffer, "BASE"))
105         {
106           strcpy (buffer, "HOME");
107         }
108       if (isdigit (buffer[0]))
109         {
110           /* Arg was a bank number.  Handle in an ASM independent
111              way. */
112           char num[128];
113           strcpy (num, sz + 5);
114           _chomp (num);
115
116           switch (_G.asmType)
117             {
118             case ASM_TYPE_ASXXXX:
119               sprintf (buffer, "CODE_%s", num);
120               break;
121             case ASM_TYPE_RGBDS:
122               sprintf (buffer, "CODE,BANK[%s]", num);
123               break;
124             case ASM_TYPE_ISAS:
125               /* PENDING: what to use for ISAS? */
126               sprintf (buffer, "CODE,BANK(%s)", num);
127               break;
128             default:
129               wassert (0);
130             }
131         }
132       gbz80_port.mem.code_name = gc_strdup (buffer);
133       code->sname = gbz80_port.mem.code_name;
134       return 0;
135     }
136   return 1;
137 }
138
139 static const char *_gbz80_rgbasmCmd[] =
140 {
141   "rgbasm", "-o$1.o", "$1.asm", NULL
142 };
143
144 static const char *_gbz80_rgblinkCmd[] =
145 {
146   "xlink", "-tg", "-n$1.sym", "-m$1.map", "-zFF", "$1.lnk", NULL
147 };
148
149 static void
150 _gbz80_rgblink (void)
151 {
152   FILE *lnkfile;
153   const char *sz;
154
155   int i;
156   sz = srcFileName;
157   if (!sz)
158     sz = "a";
159
160   /* first we need to create the <filename>.lnk file */
161   sprintf (scratchFileName, "%s.lnk", sz);
162   if (!(lnkfile = fopen (scratchFileName, "w")))
163     {
164       werror (E_FILE_OPEN_ERR, scratchFileName);
165       exit (1);
166     }
167
168   fprintf (lnkfile, "[Objects]\n");
169
170   if (srcFileName)
171     fprintf (lnkfile, "%s.o\n", sz);
172
173   for (i = 0; i < nrelFiles; i++)
174     fprintf (lnkfile, "%s\n", relFiles[i]);
175
176   fprintf (lnkfile, "\n[Libraries]\n");
177   /* additional libraries if any */
178   for (i = 0; i < nlibFiles; i++)
179     fprintf (lnkfile, "%s\n", libFiles[i]);
180
181
182   fprintf (lnkfile, "\n[Output]\n" "%s.gb", sz);
183
184   fclose (lnkfile);
185
186   buildCmdLine (buffer,port->linker.cmd, sz, NULL, NULL, NULL);
187   /* call the linker */
188   if (my_system (buffer))
189     {
190       perror ("Cannot exec linker");
191       exit (1);
192     }
193 }
194
195 static bool
196 _parseOptions (int *pargc, char **argv, int *i)
197 {
198   if (argv[*i][0] == '-')
199     {
200       if (argv[*i][1] == 'b' && IS_GB)
201         {
202           int bank = atoi (argv[*i] + 3);
203           char buffer[128];
204           switch (argv[*i][2])
205             {
206             case 'o':
207               /* ROM bank */
208               sprintf (buffer, "CODE_%u", bank);
209               gbz80_port.mem.code_name = gc_strdup (buffer);
210               return TRUE;
211             case 'a':
212               /* RAM bank */
213               sprintf (buffer, "DATA_%u", bank);
214               gbz80_port.mem.data_name = gc_strdup (buffer);
215               return TRUE;
216             }
217         }
218       else if (!strncmp (argv[*i], "--asm=", 6))
219         {
220           if (!strcmp (argv[*i], "--asm=rgbds"))
221             {
222               asm_addTree (&_rgbds_gb);
223               gbz80_port.assembler.cmd = _gbz80_rgbasmCmd;
224               gbz80_port.linker.cmd = _gbz80_rgblinkCmd;
225               gbz80_port.linker.do_link = _gbz80_rgblink;
226               _G.asmType = ASM_TYPE_RGBDS;
227               return TRUE;
228             }
229           else if (!strcmp (argv[*i], "--asm=asxxxx"))
230             {
231               _G.asmType = ASM_TYPE_ASXXXX;
232               return TRUE;
233             }
234           else if (!strcmp (argv[*i], "--asm=isas"))
235             {
236               asm_addTree (&_isas_gb);
237               /* Munge the function prefix */
238               gbz80_port.fun_prefix = "";
239               _G.asmType = ASM_TYPE_ISAS;
240               return TRUE;
241             }
242         }
243     }
244   return FALSE;
245 }
246
247 static void
248 _finaliseOptions (void)
249 {
250   port->mem.default_local_map = data;
251   port->mem.default_globl_map = data;
252   if (_G.asmType == ASM_TYPE_ASXXXX && IS_GB)
253     asm_addTree (&_asxxxx_gb);
254 }
255
256 static void
257 _setDefaultOptions (void)
258 {
259   options.genericPtr = 1;       /* default on */
260   options.nopeep = 0;
261   options.stackAuto = 1;
262   options.mainreturn = 1;
263   /* first the options part */
264   options.intlong_rent = 1;
265
266   /* Default code and data locations. */
267   options.code_loc = 0x200;
268   options.data_loc = 0x8000;
269
270   optimize.global_cse = 1;
271   optimize.label1 = 1;
272   optimize.label2 = 1;
273   optimize.label3 = 1;
274   optimize.label4 = 1;
275   optimize.loopInvariant = 1;
276   optimize.loopInduction = 0;
277 }
278
279 static const char *
280 _getRegName (struct regs *reg)
281 {
282   if (reg)
283     return reg->name;
284   assert (0);
285   return "err";
286 }
287
288 /** $1 is always the basename.
289     $2 is always the output file.
290     $3 varies
291     $l is the list of extra options that should be there somewhere...
292     MUST be terminated with a NULL.
293 */
294 static const char *_z80_linkCmd[] =
295 {
296     "link-z80", 
297     "-n",                       // Don't echo output
298     "-c",                       // Command line input
299     "--",                       // Again, command line input...
300     "-b_CODE=0x200",            // Code starts at 0x200
301     "-b_DATA=0x8000",           // RAM starts at 0x8000
302     "-j",                       // Output a symbol file as well
303     "-k" SDCC_LIB_DIR "/z80",   // Library path
304     "-lz80.lib",                // Library to use
305     "-i",                       // Output Intel IHX
306     "$1.ihx",                   // Output to
307     SDCC_LIB_DIR "/z80/crt0.o", // Link in crt0 first
308     "$1.o",                     // Actual code
309     NULL
310 };
311
312 /* sprintf that appends to the string. */
313 static void
314 _saprintf(char *pinto, const char *format, ...)
315 {
316     va_list ap;
317     va_start(ap, format);
318
319     vsprintf(pinto + strlen(pinto), format, ap);
320     va_end(ap);
321 }
322
323 static void
324 _z80_link(void)
325 {
326     int i;
327     // PENDING
328     char buffer[2048];
329
330     sprintf(buffer, 
331             "link-z80 "
332             "-n "                       // Don't echo output
333             "-c "                       // Command line input
334             "-- "                       // Again, command line input...
335             "-b_CODE=0x%04X "           // Code starts at 0x200
336             "-b_DATA=0x%04X "           // RAM starts at 0x8000
337             "-j ",                      // Output a symbol file as well
338             options.code_loc,
339             options.data_loc
340             );
341
342     // Add the standard lib in.
343     if (options.nostdlib == FALSE) {
344         _saprintf(buffer,
345                   "-k" SDCC_LIB_DIR "/z80 "   // Library path
346                   "-lz80.lib "                // Library to use
347                   );
348     }
349
350     // Add in the library paths and libraries
351     for (i = 0; i < nlibFiles; i++) {
352         _saprintf(buffer, "-k%s ", libFiles[i]);
353     }
354     for (i = 0; i < nlibPaths; i++) {
355         _saprintf(buffer, "-l%s ", libPaths[i]);
356     }
357
358     _saprintf(buffer,
359               "-i "                       // Output Intel IHX
360               "%s.ihx ",                  // Output to
361               srcFileName
362               );
363
364     if (options.nostdlib == FALSE) {
365         _saprintf(buffer, 
366                   SDCC_LIB_DIR "/z80/crt0.o " // Link in crt0 first
367                   );
368     }
369
370     _saprintf(buffer,
371               "%s.o ",                    // Actual code
372               srcFileName
373               );
374
375     // Append all the other targets
376     for (i = 0; i < nrelFiles; i++) {
377         _saprintf(buffer, "%s ", relFiles[i]);
378     }
379
380     // Do it.
381     if (my_system (buffer)) {
382         exit(1);
383     }
384 }
385
386 static const char *_z80_asmCmd[] =
387 {
388     "as-z80", "-plosgff", "$1.o", "$1.asm", NULL
389 };
390
391 /** $1 is always the basename.
392     $2 is always the output file.
393     $3 varies
394     $l is the list of extra options that should be there somewhere...
395     MUST be terminated with a NULL.
396 */
397 static const char *_gbz80_linkCmd[] =
398 {
399     // PENDING
400     "link-gbz80", "-nf", "$1", NULL
401 };
402
403 static const char *_gbz80_asmCmd[] =
404 {
405     "as-gbz80", "-plosgff", "$1.o", "$1.asm", NULL
406 };
407
408 /* Globals */
409 PORT z80_port =
410 {
411   TARGET_ID_Z80,
412   "z80",
413   "Zilog Z80",                  /* Target name */
414   {
415     FALSE,
416     MODEL_MEDIUM | MODEL_SMALL,
417     MODEL_SMALL
418   },
419   {
420     _z80_asmCmd,
421     "-plosgff",                 /* Options with debug */
422     "-plosgff",                 /* Options without debug */
423     0,
424     ".asm"
425   },
426   {
427     _z80_linkCmd,
428     _z80_link,
429     ".o"
430   },
431   {
432     _z80_defaultRules
433   },
434   {
435         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
436     1, 2, 2, 4, 2, 2, 2, 1, 4, 4
437   },
438   {
439     "XSEG",
440     "STACK",
441     "CODE",
442     "DATA",
443     "ISEG",
444     "XSEG",
445     "BSEG",
446     "RSEG",
447     "GSINIT",
448     "OVERLAY",
449     "GSFINAL",
450     "HOME",
451     NULL,
452     NULL,
453     1
454   },
455   {
456     -1, 0, 0, 4, 0, 2
457   },
458     /* Z80 has no native mul/div commands */
459   {
460     0, 2
461   },
462   "_",
463   _z80_init,
464   _parseOptions,
465   _finaliseOptions,
466   _setDefaultOptions,
467   z80_assignRegisters,
468   _getRegName,
469   _keywords,
470   0,                            /* no assembler preamble */
471   0,                            /* no local IVT generation code */
472   _reset_regparm,
473   _reg_parm,
474   _process_pragma,
475   TRUE,
476   0,                            /* leave lt */
477   0,                            /* leave gt */
478   1,                            /* transform <= to ! > */
479   1,                            /* transform >= to ! < */
480   1,                            /* transform != to !(a == b) */
481   0,                            /* leave == */
482   PORT_MAGIC
483 };
484
485 /* Globals */
486 PORT gbz80_port =
487 {
488   TARGET_ID_GBZ80,
489   "gbz80",
490   "Gameboy Z80-like",           /* Target name */
491   {
492     FALSE,
493     MODEL_MEDIUM | MODEL_SMALL,
494     MODEL_SMALL
495   },
496   {
497     _gbz80_asmCmd,
498     "-plosgff",                 /* Options with debug */
499     "-plosgff",                 /* Options without debug */
500     1,
501     ".asm"
502   },
503   {
504     _gbz80_linkCmd,
505     NULL,
506     ".o"
507   },
508   {
509     _gbz80_defaultRules
510   },
511   {
512         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
513     1, 1, 2, 4, 2, 2, 2, 1, 4, 4
514   },
515   {
516     "XSEG",
517     "STACK",
518     "CODE",
519     "DATA",
520     "ISEG",
521     "XSEG",
522     "BSEG",
523     "RSEG",
524     "GSINIT",
525     "OVERLAY",
526     "GSFINAL",
527     "HOME",
528     NULL,
529     NULL,
530     1
531   },
532   {
533     -1, 0, 0, 2, 0, 4
534   },
535     /* gbZ80 has no native mul/div commands */
536   {
537     0, 2
538   },
539   "_",
540   _gbz80_init,
541   _parseOptions,
542   _finaliseOptions,
543   _setDefaultOptions,
544   z80_assignRegisters,
545   _getRegName,
546   _keywords,
547   0,                            /* no assembler preamble */
548   0,                            /* no local IVT generation code */
549   _reset_regparm,
550   _reg_parm,
551   _process_pragma,
552   TRUE,
553   0,                            /* leave lt */
554   0,                            /* leave gt */
555   1,                            /* transform <= to ! > */
556   1,                            /* transform >= to ! < */
557   1,                            /* transform != to !(a == b) */
558   0,                            /* leave == */
559   PORT_MAGIC
560 };