Added link support in the simple case
[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   optimize.global_cse = 1;
267   optimize.label1 = 1;
268   optimize.label2 = 1;
269   optimize.label3 = 1;
270   optimize.label4 = 1;
271   optimize.loopInvariant = 1;
272   optimize.loopInduction = 0;
273 }
274
275 static const char *
276 _getRegName (struct regs *reg)
277 {
278   if (reg)
279     return reg->name;
280   assert (0);
281   return "err";
282 }
283
284 /** $1 is always the basename.
285     $2 is always the output file.
286     $3 varies
287     $l is the list of extra options that should be there somewhere...
288     MUST be terminated with a NULL.
289 */
290 static const char *_z80_linkCmd[] =
291 {
292     "link-z80", 
293     "-n",                       // Don't echo output
294     "-c",                       // Command line input
295     "--",                       // Again, command line input...
296     "-b_CODE=0x200",            // Code starts at 0x200
297     "-b_DATA=0x8000",           // RAM starts at 0x8000
298     "-j",                       // Output a symbol file as well
299     "-k" SDCC_LIB_DIR "/z80",   // Library path
300     "-lz80.lib",                // Library to use
301     "-i",                       // Output Intel IHX
302     "$1.ihx",                   // Output to
303     SDCC_LIB_DIR "/z80/crt0.o", // Link in crt0 first
304     "$1.o",                     // Actual code
305     NULL
306 };
307
308 static const char *_z80_asmCmd[] =
309 {
310     "as-z80", "-plosgff", "$1.o", "$1.asm", NULL
311 };
312
313 /** $1 is always the basename.
314     $2 is always the output file.
315     $3 varies
316     $l is the list of extra options that should be there somewhere...
317     MUST be terminated with a NULL.
318 */
319 static const char *_gbz80_linkCmd[] =
320 {
321     // PENDING
322     "link-gbz80", "-nf", "$1", NULL
323 };
324
325 static const char *_gbz80_asmCmd[] =
326 {
327     "as-gbz80", "-plosgff", "$1.o", "$1.asm", NULL
328 };
329
330 /* Globals */
331 PORT z80_port =
332 {
333   TARGET_ID_Z80,
334   "z80",
335   "Zilog Z80",                  /* Target name */
336   {
337     FALSE,
338     MODEL_MEDIUM | MODEL_SMALL,
339     MODEL_SMALL
340   },
341   {
342     _z80_asmCmd,
343     "-plosgff",                 /* Options with debug */
344     "-plosgff",                 /* Options without debug */
345     0,
346     ".asm"
347   },
348   {
349     _z80_linkCmd,
350     NULL,
351     ".o"
352   },
353   {
354     _z80_defaultRules
355   },
356   {
357         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
358     1, 2, 2, 4, 2, 2, 2, 1, 4, 4
359   },
360   {
361     "XSEG",
362     "STACK",
363     "CODE",
364     "DATA",
365     "ISEG",
366     "XSEG",
367     "BSEG",
368     "RSEG",
369     "GSINIT",
370     "OVERLAY",
371     "GSFINAL",
372     "HOME",
373     NULL,
374     NULL,
375     1
376   },
377   {
378     -1, 0, 0, 4, 0, 2
379   },
380     /* Z80 has no native mul/div commands */
381   {
382     0, 2
383   },
384   "_",
385   _z80_init,
386   _parseOptions,
387   _finaliseOptions,
388   _setDefaultOptions,
389   z80_assignRegisters,
390   _getRegName,
391   _keywords,
392   0,                            /* no assembler preamble */
393   0,                            /* no local IVT generation code */
394   _reset_regparm,
395   _reg_parm,
396   _process_pragma,
397   TRUE,
398   0,                            /* leave lt */
399   0,                            /* leave gt */
400   1,                            /* transform <= to ! > */
401   1,                            /* transform >= to ! < */
402   1,                            /* transform != to !(a == b) */
403   0,                            /* leave == */
404   PORT_MAGIC
405 };
406
407 /* Globals */
408 PORT gbz80_port =
409 {
410   TARGET_ID_GBZ80,
411   "gbz80",
412   "Gameboy Z80-like",           /* Target name */
413   {
414     FALSE,
415     MODEL_MEDIUM | MODEL_SMALL,
416     MODEL_SMALL
417   },
418   {
419     _gbz80_asmCmd,
420     "-plosgff",                 /* Options with debug */
421     "-plosgff",                 /* Options without debug */
422     1,
423     ".asm"
424   },
425   {
426     _gbz80_linkCmd,
427     NULL,
428     ".o"
429   },
430   {
431     _gbz80_defaultRules
432   },
433   {
434         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
435     1, 1, 2, 4, 2, 2, 2, 1, 4, 4
436   },
437   {
438     "XSEG",
439     "STACK",
440     "CODE",
441     "DATA",
442     "ISEG",
443     "XSEG",
444     "BSEG",
445     "RSEG",
446     "GSINIT",
447     "OVERLAY",
448     "GSFINAL",
449     "HOME",
450     NULL,
451     NULL,
452     1
453   },
454   {
455     -1, 0, 0, 2, 0, 4
456   },
457     /* gbZ80 has no native mul/div commands */
458   {
459     0, 2
460   },
461   "_",
462   _gbz80_init,
463   _parseOptions,
464   _finaliseOptions,
465   _setDefaultOptions,
466   z80_assignRegisters,
467   _getRegName,
468   _keywords,
469   0,                            /* no assembler preamble */
470   0,                            /* no local IVT generation code */
471   _reset_regparm,
472   _reg_parm,
473   _process_pragma,
474   TRUE,
475   0,                            /* leave lt */
476   0,                            /* leave gt */
477   1,                            /* transform <= to ! > */
478   1,                            /* transform >= to ! < */
479   1,                            /* transform != to !(a == b) */
480   0,                            /* leave == */
481   PORT_MAGIC
482 };