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