f27157b28e7b6d9f1f8a26d2e7c7f0a060585c0a
[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 (options.noRegParams) 
72     {
73       return FALSE;
74     }
75   else 
76     {
77       if (regParmFlg == 2)
78         {
79           return FALSE;
80         }
81       else
82         {
83           regParmFlg++;
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   options.data_loc = 0x8000;
280
281   optimize.global_cse = 1;
282   optimize.label1 = 1;
283   optimize.label2 = 1;
284   optimize.label3 = 1;
285   optimize.label4 = 1;
286   optimize.loopInvariant = 1;
287   optimize.loopInduction = 0;
288 }
289
290 /* Mangaling format:
291     _fun_policy_params
292     where:
293       policy is the function policy
294       params is the parameter format
295
296    policy format:
297     rsp
298     where:
299       r is 'r' for reentrant, 's' for static functions
300       s is 'c' for callee saves, 'r' for caller saves
301       p is 'p' for profiling on, 'x' for profiling off
302     examples:
303       rr - reentrant, caller saves
304    params format:
305     A combination of register short names and s to signify stack variables.
306     examples:
307       bds - first two args appear in BC and DE, the rest on the stack
308       s - all arguments are on the stack.
309 */
310 static char *
311 _mangleSupportFunctionName(char *original)
312 {
313   char buffer[128];
314
315   if (TARGET_IS_Z80) 
316     {
317       sprintf(buffer, "%s_rr%s_%s", original,
318               options.profile ? "f" : "x",
319               options.noRegParams ? "s" : "bds"
320               );
321     }
322   else 
323     {
324       strcpy(buffer, original);
325     }
326
327   return gc_strdup(buffer);
328 }
329
330 static const char *
331 _getRegName (struct regs *reg)
332 {
333   if (reg)
334     return reg->name;
335   assert (0);
336   return "err";
337 }
338
339 /** $1 is always the basename.
340     $2 is always the output file.
341     $3 varies
342     $l is the list of extra options that should be there somewhere...
343     MUST be terminated with a NULL.
344 */
345 static const char *_z80_linkCmd[] =
346 {
347     "link-z80", 
348     "-n",                       // Don't echo output
349     "-c",                       // Command line input
350     "--",                       // Again, command line input...
351     "-b_CODE=0x200",            // Code starts at 0x200
352     "-b_DATA=0x8000",           // RAM starts at 0x8000
353     "-j",                       // Output a symbol file as well
354     "-k" SDCC_LIB_DIR "/z80",   // Library path
355     "-lz80.lib",                // Library to use
356     "-i",                       // Output Intel IHX
357     "$1.ihx",                   // Output to
358     SDCC_LIB_DIR "/z80/crt0.o", // Link in crt0 first
359     "$1.o",                     // Actual code
360     NULL
361 };
362
363 /* sprintf that appends to the string. */
364 static void
365 _saprintf(char *pinto, const char *format, ...)
366 {
367     va_list ap;
368     va_start(ap, format);
369
370     vsprintf(pinto + strlen(pinto), format, ap);
371     va_end(ap);
372 }
373
374 static void
375 _z80_link(void)
376 {
377     int i;
378     // PENDING
379     char buffer[2048];
380
381     sprintf(buffer, 
382             "link-z80 "
383             "-n "                       // Don't echo output
384             "-c "                       // Command line input
385             "-- "                       // Again, command line input...
386             "-b_CODE=0x%04X "           // Code starts at 0x200
387             "-b_DATA=0x%04X "           // RAM starts at 0x8000
388             "-j ",                      // Output a symbol file as well
389             options.code_loc,
390             options.data_loc
391             );
392
393     // Add the standard lib in.
394     if (options.nostdlib == FALSE) {
395         _saprintf(buffer,
396                   "-k" SDCC_LIB_DIR "/z80 "   // Library path
397                   "-lz80.lib "                // Library to use
398                   );
399     }
400
401     // Add in the library paths and libraries
402     for (i = 0; i < nlibFiles; i++) {
403         _saprintf(buffer, "-k%s ", libFiles[i]);
404     }
405     for (i = 0; i < nlibPaths; i++) {
406         _saprintf(buffer, "-l%s ", libPaths[i]);
407     }
408
409     _saprintf(buffer,
410               "-i "                       // Output Intel IHX
411               "%s.ihx ",                  // Output to
412               srcFileName
413               );
414
415     if (options.nostdlib == FALSE) {
416         _saprintf(buffer, 
417                   SDCC_LIB_DIR "/z80/crt0.o " // Link in crt0 first
418                   );
419     }
420
421     _saprintf(buffer,
422               "%s.o ",                    // Actual code
423               srcFileName
424               );
425
426     // Append all the other targets
427     for (i = 0; i < nrelFiles; i++) {
428         _saprintf(buffer, "%s ", relFiles[i]);
429     }
430
431     // Do it.
432     if (my_system (buffer)) {
433         exit(1);
434     }
435 }
436
437 static const char *_z80_asmCmd[] =
438 {
439     "as-z80", "-plosgff", "$1.o", "$1.asm", NULL
440 };
441
442 /** $1 is always the basename.
443     $2 is always the output file.
444     $3 varies
445     $l is the list of extra options that should be there somewhere...
446     MUST be terminated with a NULL.
447 */
448 static const char *_gbz80_linkCmd[] =
449 {
450     // PENDING
451     "link-gbz80", "-nf", "$1", NULL
452 };
453
454 static const char *_gbz80_asmCmd[] =
455 {
456     "as-gbz80", "-plosgff", "$1.o", "$1.asm", NULL
457 };
458
459 /* Globals */
460 PORT z80_port =
461 {
462   TARGET_ID_Z80,
463   "z80",
464   "Zilog Z80",                  /* Target name */
465   {
466     FALSE,
467     MODEL_MEDIUM | MODEL_SMALL,
468     MODEL_SMALL
469   },
470   {
471     _z80_asmCmd,
472     "-plosgff",                 /* Options with debug */
473     "-plosgff",                 /* Options without debug */
474     0,
475     ".asm"
476   },
477   {
478     _z80_linkCmd,
479     _z80_link,
480     ".o"
481   },
482   {
483     _z80_defaultRules
484   },
485   {
486         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
487     1, 2, 2, 4, 2, 2, 2, 1, 4, 4
488   },
489   {
490     "XSEG",
491     "STACK",
492     "CODE",
493     "DATA",
494     "ISEG",
495     "XSEG",
496     "BSEG",
497     "RSEG",
498     "GSINIT",
499     "OVERLAY",
500     "GSFINAL",
501     "HOME",
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   _finaliseOptions,
517   _setDefaultOptions,
518   z80_assignRegisters,
519   _getRegName,
520   _keywords,
521   0,                            /* no assembler preamble */
522   0,                            /* no local IVT generation code */
523   _reset_regparm,
524   _reg_parm,
525   _process_pragma,
526   _mangleSupportFunctionName,
527   TRUE,
528   0,                            /* leave lt */
529   0,                            /* leave gt */
530   1,                            /* transform <= to ! > */
531   1,                            /* transform >= to ! < */
532   1,                            /* transform != to !(a == b) */
533   0,                            /* leave == */
534   PORT_MAGIC
535 };
536
537 /* Globals */
538 PORT gbz80_port =
539 {
540   TARGET_ID_GBZ80,
541   "gbz80",
542   "Gameboy Z80-like",           /* Target name */
543   {
544     FALSE,
545     MODEL_MEDIUM | MODEL_SMALL,
546     MODEL_SMALL
547   },
548   {
549     _gbz80_asmCmd,
550     "-plosgff",                 /* Options with debug */
551     "-plosgff",                 /* Options without debug */
552     1,
553     ".asm"
554   },
555   {
556     _gbz80_linkCmd,
557     NULL,
558     ".o"
559   },
560   {
561     _gbz80_defaultRules
562   },
563   {
564         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
565     1, 1, 2, 4, 2, 2, 2, 1, 4, 4
566   },
567   {
568     "XSEG",
569     "STACK",
570     "CODE",
571     "DATA",
572     "ISEG",
573     "XSEG",
574     "BSEG",
575     "RSEG",
576     "GSINIT",
577     "OVERLAY",
578     "GSFINAL",
579     "HOME",
580     NULL,
581     NULL,
582     1
583   },
584   {
585     -1, 0, 0, 2, 0, 4
586   },
587     /* gbZ80 has no native mul/div commands */
588   {
589     0, 2
590   },
591   "_",
592   _gbz80_init,
593   _parseOptions,
594   _finaliseOptions,
595   _setDefaultOptions,
596   z80_assignRegisters,
597   _getRegName,
598   _keywords,
599   0,                            /* no assembler preamble */
600   0,                            /* no local IVT generation code */
601   _reset_regparm,
602   _reg_parm,
603   _process_pragma,
604   NULL,
605   TRUE,
606   0,                            /* leave lt */
607   0,                            /* leave gt */
608   1,                            /* transform <= to ! > */
609   1,                            /* transform >= to ! < */
610   1,                            /* transform != to !(a == b) */
611   0,                            /* leave == */
612   PORT_MAGIC
613 };