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