057d01d5ab14190fccb3ada01a162c6657031175
[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 <sys/stat.h>
26 #include "z80.h"
27 #include "MySystem.h"
28 #include "BuildCmd.h"
29 #include "SDCCutil.h"
30 #include "dbuf.h"
31
32 static char _z80_defaultRules[] =
33 {
34 #include "peeph.rul"
35 #include "peeph-z80.rul"
36 };
37
38 static char _gbz80_defaultRules[] =
39 {
40 #include "peeph.rul"
41 #include "peeph-gbz80.rul"
42 };
43
44 Z80_OPTS z80_opts;
45
46 static OPTION _z80_options[] = 
47   {
48     {  0,   "--callee-saves-bc", &z80_opts.calleeSavesBC, "Force a called function to always save BC" },
49     {  0,   "--portmode=",       NULL,                    "Determine PORT I/O mode (z80/z180)" },
50     {  0, NULL }
51   };
52
53 static OPTION _gbz80_options[] = 
54   {
55     {  0,   "--callee-saves-bc", &z80_opts.calleeSavesBC, "Force a called function to always save BC" },
56     {  0, NULL }
57   };
58
59 typedef enum
60   {
61     /* Must be first */
62     ASM_TYPE_ASXXXX,
63     ASM_TYPE_RGBDS,
64     ASM_TYPE_ISAS,
65     ASM_TYPE_Z80ASM
66   }
67 ASM_TYPE;
68
69 static struct
70   {
71     ASM_TYPE asmType;
72     /* determine if we can register a parameter */    
73     int regParams;
74   }
75 _G;
76
77 static char *_keywords[] =
78 {
79   "sfr",
80   "nonbanked",
81   "banked",
82   "at",       //.p.t.20030714 adding support for 'sfr at ADDR' construct
83   "_naked",   //.p.t.20030714 adding support for '_naked' functions
84   "critical",
85   NULL
86 };
87
88 extern PORT gbz80_port;
89 extern PORT z80_port;
90
91 #include "mappings.i"
92
93 static builtins _z80_builtins[] = {
94   /* Disabled for now.
95     { "__builtin_strcpy", "v", 2, {"cg*", "cg*" } },
96     { "__builtin_memcpy", "cg*", 3, {"cg*", "cg*", "ui" } },
97   */
98     { NULL , NULL,0, {NULL}}
99 };    
100
101 static void
102 _z80_init (void)
103 {
104   z80_opts.sub = SUB_Z80;
105   asm_addTree (&_asxxxx_z80);
106 }
107
108 static void
109 _gbz80_init (void)
110 {
111   z80_opts.sub = SUB_GBZ80;
112 }
113
114 static void
115 _reset_regparm ()
116 {
117   _G.regParams = 0;
118 }
119
120 static int
121 _reg_parm (sym_link * l)
122 {
123   if (options.noRegParams) 
124     {
125       return FALSE;
126     }
127   else 
128     {
129       if (_G.regParams == 2)
130         {
131           return FALSE;
132         }
133       else
134         {
135           _G.regParams++;
136           return TRUE;
137         }
138     }
139 }
140 static int
141 _process_pragma (const char *sz)
142 {
143   if( startsWith( sz, "bank=" ) || startsWith( sz, "bank " ))
144   {
145     char buffer[128];
146     
147     if (sz[4]=='=')
148       werror(W_DEPRECATED_PRAGMA, "bank=");
149     
150     strncpy (buffer, sz + 5, sizeof (buffer));
151     buffer[sizeof (buffer) - 1 ] = '\0';
152     chomp (buffer);
153     if (isdigit (buffer[0]))
154     {
155
156     }
157     else if (!strcmp (buffer, "BASE"))
158     {
159       strcpy (buffer, "HOME");
160     }
161     if (isdigit (buffer[0]))
162     {
163           /* Arg was a bank number.  Handle in an ASM independent
164              way. */
165       char num[128];
166       strncpy (num, sz + 5, sizeof (num));
167       num[sizeof (num) -1] = '\0';
168       chomp (num);
169
170       switch (_G.asmType)
171       {
172             case ASM_TYPE_ASXXXX:
173               sprintf (buffer, "CODE_%s", num);
174               break;
175             case ASM_TYPE_RGBDS:
176               sprintf (buffer, "CODE,BANK[%s]", num);
177               break;
178             case ASM_TYPE_ISAS:
179               /* PENDING: what to use for ISAS? */
180               sprintf (buffer, "CODE,BANK(%s)", num);
181               break;
182             default:
183               wassert (0);
184       }
185     }
186     gbz80_port.mem.code_name = Safe_strdup (buffer);
187     code->sname = gbz80_port.mem.code_name;
188     return 0;
189   }
190   else if( startsWith( sz, "portmode=" ) || startsWith( sz, "portmode " ))
191   { /*.p.t.20030716 - adding pragma to manipulate z80 i/o port addressing modes */
192     char bfr[128];
193
194     if (sz[8]=='=')
195       werror(W_DEPRECATED_PRAGMA, "portmode=");
196
197     strncpy( bfr, sz + 9, sizeof (bfr));
198     bfr[sizeof (bfr) - 1] = '\0';
199     chomp( bfr );
200
201     if     ( !strcmp( bfr, "z80"     )){ z80_opts.port_mode =  80; }
202     else if( !strcmp( bfr, "z180"    )){ z80_opts.port_mode = 180; }
203     else if( !strcmp( bfr, "save"    )){ z80_opts.port_back = z80_opts.port_mode; }
204     else if( !strcmp( bfr, "restore" )){ z80_opts.port_mode = z80_opts.port_back; }
205     else                                 return( 1 );
206
207     return( 0 );
208   }
209
210   return 1;
211 }
212
213 static const char *_gbz80_rgbasmCmd[] =
214 {
215   "rgbasm", "-o\"$1.o\"", "\"$1.asm\"", NULL
216 };
217
218 static const char *_gbz80_rgblinkCmd[] =
219 {
220   "xlink", "-tg", "-n\"$1.sym\"", "-m\"$1.map\"", "-zFF", "\"$1.lnk\"", NULL
221 };
222
223 static void
224 _gbz80_rgblink (void)
225 {
226   FILE *lnkfile;
227
228   /* first we need to create the <filename>.lnk file */
229   sprintf (scratchFileName, "%s.lnk", dstFileName);
230   if (!(lnkfile = fopen (scratchFileName, "w")))
231     {
232       werror (E_FILE_OPEN_ERR, scratchFileName);
233       exit (1);
234     }
235
236   fprintf (lnkfile, "[Objects]\n");
237
238   fprintf (lnkfile, "%s.o\n", dstFileName);
239
240   fputStrSet(lnkfile, relFilesSet);
241
242   fprintf (lnkfile, "\n[Libraries]\n");
243   /* additional libraries if any */
244   fputStrSet(lnkfile, libFilesSet);
245
246   fprintf (lnkfile, "\n[Output]\n" "%s.gb", dstFileName);
247
248   fclose (lnkfile);
249
250   buildCmdLine (buffer,port->linker.cmd, dstFileName, NULL, NULL, NULL);
251   /* call the linker */
252   if (my_system (buffer))
253     {
254       perror ("Cannot exec linker");
255       exit (1);
256     }
257 }
258
259 static bool
260 _parseOptions (int *pargc, char **argv, int *i)
261 {
262   if (argv[*i][0] == '-')
263     {
264       if (argv[*i][1] == 'b' && IS_GB)
265         {
266           int bank = atoi (argv[*i] + 3);
267           char buffer[128];
268           switch (argv[*i][2])
269             {
270             case 'o':
271               /* ROM bank */
272               sprintf (buffer, "CODE_%u", bank);
273               gbz80_port.mem.code_name = Safe_strdup (buffer);
274               return TRUE;
275             case 'a':
276               /* RAM bank */
277               sprintf (buffer, "DATA_%u", bank);
278               gbz80_port.mem.data_name = Safe_strdup (buffer);
279               return TRUE;
280             }
281         }
282       else if (!strncmp (argv[*i], "--asm=", 6))
283         {
284           if (!strcmp (argv[*i], "--asm=rgbds"))
285             {
286               asm_addTree (&_rgbds_gb);
287               gbz80_port.assembler.cmd = _gbz80_rgbasmCmd;
288               gbz80_port.linker.cmd = _gbz80_rgblinkCmd;
289               gbz80_port.linker.do_link = _gbz80_rgblink;
290               _G.asmType = ASM_TYPE_RGBDS;
291               return TRUE;
292             }
293           else if (!strcmp (argv[*i], "--asm=asxxxx"))
294             {
295               _G.asmType = ASM_TYPE_ASXXXX;
296               return TRUE;
297             }
298           else if (!strcmp (argv[*i], "--asm=isas"))
299             {
300               asm_addTree (&_isas_gb);
301               /* Munge the function prefix */
302               gbz80_port.fun_prefix = "";
303               _G.asmType = ASM_TYPE_ISAS;
304               return TRUE;
305             }
306           else if (!strcmp (argv[*i], "--asm=z80asm"))
307             {
308               port->assembler.externGlobal = TRUE;
309               asm_addTree (&_z80asm_z80);
310               _G.asmType = ASM_TYPE_ISAS;
311               return TRUE;
312             }
313         }
314       else if (!strncmp (argv[*i], "--portmode=", 11))
315         {
316           if (!strcmp (argv[*i], "--portmode=z80"))
317             {
318               z80_opts.port_mode =  80;
319               return TRUE;
320             }
321           else if (!strcmp (argv[*i], "--portmode=z180"))
322             {
323               z80_opts.port_mode =  180;
324               return TRUE;
325             }
326          }
327     }
328   return FALSE;
329 }
330
331 static void
332 _setValues(void)
333 {
334   const char *s;
335
336   if (options.nostdlib == FALSE)
337     {
338       const char *s;
339       char path[PATH_MAX];
340       struct dbuf_s dbuf;
341
342       dbuf_init(&dbuf, PATH_MAX);
343
344       for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
345         {
346           buildCmdLine2(path, sizeof path, "-k\"%s" DIR_SEPARATOR_STRING "{port}\" ", s);
347           dbuf_append(&dbuf, path, strlen(path));
348         }
349       buildCmdLine2(path, sizeof path, "-l\"{port}.lib\"", s);
350       dbuf_append(&dbuf, path, strlen(path));
351
352       setMainValue ("z80libspec", dbuf_c_str(&dbuf));
353       dbuf_destroy(&dbuf);
354
355       for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
356         {
357           struct stat stat_buf;
358
359           buildCmdLine2(path, sizeof path, "%s" DIR_SEPARATOR_STRING "{port}" DIR_SEPARATOR_STRING "crt0{objext}", s);
360           if (stat(path, &stat_buf) == 0)
361             break;
362         }
363
364       if (s == NULL)
365         setMainValue ("z80crt0", "\"crt0{objext}\"");
366       else
367         {
368           char *buf;
369           size_t len = strlen(path) + 3;
370
371           buf = Safe_alloc(len);
372           SNPRINTF(buf, len, "\"%s\"", path);
373           setMainValue("z80crt0", buf);
374           Safe_free(buf);
375         } 
376     }
377   else
378     {
379       setMainValue ("z80libspec", "");
380       setMainValue ("z80crt0", "");
381     }
382
383   setMainValue ("z80extralibfiles", (s = joinStrSet(libFilesSet)));
384   Safe_free((void *)s);
385   setMainValue ("z80extralibpaths", (s = joinStrSet(libPathsSet)));
386   Safe_free((void *)s);
387
388   if (IS_GB)
389     {
390       setMainValue ("z80outputtypeflag", "-z");
391       setMainValue ("z80outext", ".gb");
392     }
393   else
394     {
395       setMainValue ("z80outputtypeflag", "-i");
396       setMainValue ("z80outext", ".ihx");
397     }
398
399   setMainValue ("stdobjdstfilename" , "{dstfilename}{objext}");
400   setMainValue ("stdlinkdstfilename", "{dstfilename}{z80outext}");
401
402   setMainValue ("z80extraobj", (s = joinStrSet(relFilesSet)));
403   Safe_free((void *)s);
404
405   sprintf (buffer, "-b_CODE=0x%04X -b_DATA=0x%04X", options.code_loc, options.data_loc);
406   setMainValue ("z80bases", buffer);
407 }
408
409 static void
410 _finaliseOptions (void)
411 {
412   port->mem.default_local_map = data;
413   port->mem.default_globl_map = data;
414   if (_G.asmType == ASM_TYPE_ASXXXX && IS_GB)
415     asm_addTree (&_asxxxx_gb);
416
417   _setValues();
418 }
419
420 static void
421 _setDefaultOptions (void)
422 {
423   options.nopeep = 0;
424   options.stackAuto = 1;
425   options.mainreturn = 1;
426   /* first the options part */
427   options.intlong_rent = 1;
428   options.float_rent = 1;
429   options.noRegParams = 1;
430   /* Default code and data locations. */
431   options.code_loc = 0x200;
432
433   if (IS_GB) 
434     {
435       options.data_loc = 0xC000;
436     }
437   else
438     {
439       options.data_loc = 0x8000;
440     }
441
442   optimize.global_cse = 1;
443   optimize.label1 = 1;
444   optimize.label2 = 1;
445   optimize.label3 = 1;
446   optimize.label4 = 1;
447   optimize.loopInvariant = 1;
448   optimize.loopInduction = 1;
449 }
450
451 /* Mangaling format:
452     _fun_policy_params
453     where:
454       policy is the function policy
455       params is the parameter format
456
457    policy format:
458     rsp
459     where:
460       r is 'r' for reentrant, 's' for static functions
461       s is 'c' for callee saves, 'r' for caller saves
462       p is 'p' for profiling on, 'x' for profiling off
463     examples:
464       rr - reentrant, caller saves
465    params format:
466     A combination of register short names and s to signify stack variables.
467     examples:
468       bds - first two args appear in BC and DE, the rest on the stack
469       s - all arguments are on the stack.
470 */
471 static char *
472 _mangleSupportFunctionName(char *original)
473 {
474   char buffer[128];
475
476   sprintf(buffer, "%s_rr%s_%s", original,
477           options.profile ? "f" : "x",
478           options.noRegParams ? "s" : "bds"
479           );
480
481   return Safe_strdup(buffer);
482 }
483
484 static const char *
485 _getRegName (struct regs *reg)
486 {
487   if (reg)
488     {
489       return reg->name;
490     }
491   /*  assert (0); */
492   return "err";
493 }
494
495 static bool
496 _hasNativeMulFor (iCode *ic, sym_link *left, sym_link *right)
497 {
498   sym_link *test = NULL;
499   value *val;
500
501   if ( ic->op != '*')
502     {
503       return FALSE;
504     }
505
506   if ( IS_LITERAL (left))
507     {
508       test = left;
509       val = OP_VALUE (IC_LEFT (ic));
510     }
511   else if ( IS_LITERAL (right))
512     {
513       test = left;
514       val = OP_VALUE (IC_RIGHT (ic));
515     }
516   else
517     {
518       return FALSE;
519     }
520
521   if ( getSize (test) <= 2)
522     {
523       return TRUE;
524     }
525
526   return FALSE;
527 }
528
529 /* Indicate which extended bit operations this port supports */
530 static bool
531 hasExtBitOp (int op, int size)
532 {
533   if (op == GETHBIT)
534     return TRUE;
535   else
536     return FALSE;
537 }
538
539 /* Indicate the expense of an access to an output storage class */
540 static int
541 oclsExpense (struct memmap *oclass)
542 {
543   if (IN_FARSPACE(oclass))
544     return 1;
545     
546   return 0;
547 }
548
549
550 #define LINKCMD "link-{port} -nf {dstfilename}"
551 /*
552 #define LINKCMD \
553     "link-{port} -n -c -- {z80bases} -m -j" \
554     " {z80libspec}" \
555     " {z80extralibfiles} {z80extralibpaths}" \
556     " {z80outputtypeflag} \"{linkdstfilename}\"" \
557     " {z80crt0}" \
558     " \"{dstfilename}{objext}\"" \
559     " {z80extraobj}"
560 */
561
562 #define ASMCMD \
563     "as-{port} -plosgff \"{objdstfilename}\" \"{dstfilename}{asmext}\""
564
565 /* Globals */
566 PORT z80_port =
567 {
568   TARGET_ID_Z80,
569   "z80",
570   "Zilog Z80",                  /* Target name */
571   NULL,                         /* Processor name */
572   {
573     glue,
574     FALSE,
575     MODEL_MEDIUM | MODEL_SMALL,
576     MODEL_SMALL
577   },
578   {
579     NULL,
580     ASMCMD,
581     "-plosgff",                 /* Options with debug */
582     "-plosgff",                 /* Options without debug */
583     0,
584     ".asm"
585   },
586   {
587     NULL,
588     LINKCMD,
589     NULL,
590     ".o",
591     1
592   },
593   {
594     _z80_defaultRules
595   },
596   {
597         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
598     1, 2, 2, 4, 2, 2, 2, 1, 4, 4
599   },
600   {
601     "XSEG",
602     "STACK",
603     "CODE",
604     "DATA",
605     "ISEG",
606     "XSEG",
607     "BSEG",
608     "RSEG",
609     "GSINIT",
610     "OVERLAY",
611     "GSFINAL",
612     "HOME",
613     NULL, /* xidata */
614     NULL, /* xinit */
615     NULL,
616     NULL,
617     1
618   },
619   { NULL, NULL },
620   {
621     -1, 0, 0, 4, 0, 2
622   },
623     /* Z80 has no native mul/div commands */
624   {
625     0, 2
626   },
627   {
628     z80_emitDebuggerSymbol
629   },
630   {
631     255,        /* maxCount */
632     3,          /* sizeofElement */
633     /* The rest of these costs are bogus. They approximate */
634     /* the behavior of src/SDCCicode.c 1.207 and earlier.  */
635     {4,4,4},    /* sizeofMatchJump[] */
636     {0,0,0},    /* sizeofRangeCompare[] */
637     0,          /* sizeofSubtract */
638     3,          /* sizeofDispatch */
639   },
640   "_",
641   _z80_init,
642   _parseOptions,
643   _z80_options,
644   NULL,
645   _finaliseOptions,
646   _setDefaultOptions,
647   z80_assignRegisters,
648   _getRegName,
649   _keywords,
650   0,                            /* no assembler preamble */
651   NULL,                         /* no genAssemblerEnd */
652   0,                            /* no local IVT generation code */
653   0,                            /* no genXINIT code */
654   NULL,                         /* genInitStartup */
655   _reset_regparm,
656   _reg_parm,
657   _process_pragma,
658   _mangleSupportFunctionName,
659   _hasNativeMulFor,
660   hasExtBitOp,                  /* hasExtBitOp */
661   oclsExpense,                  /* oclsExpense */
662   TRUE,
663   TRUE,                         /* little endian */
664   0,                            /* leave lt */
665   0,                            /* leave gt */
666   1,                            /* transform <= to ! > */
667   1,                            /* transform >= to ! < */
668   1,                            /* transform != to !(a == b) */
669   0,                            /* leave == */
670   TRUE,                         /* Array initializer support. */        
671   0,                            /* no CSE cost estimation yet */
672   _z80_builtins,                /* no builtin functions */
673   GPOINTER,                     /* treat unqualified pointers as "generic" pointers */
674   1,                            /* reset labelKey to 1 */
675   1,                            /* globals & local static allowed */
676   PORT_MAGIC
677 };
678
679 /* Globals */
680 PORT gbz80_port =
681 {
682   TARGET_ID_GBZ80,
683   "gbz80",
684   "Gameboy Z80-like",           /* Target name */
685   NULL,
686   {
687     glue,
688     FALSE,
689     MODEL_MEDIUM | MODEL_SMALL,
690     MODEL_SMALL
691   },
692   {
693     NULL,
694     ASMCMD,
695     "-plosgff",                 /* Options with debug */
696     "-plosgff",                 /* Options without debug */
697     0,
698     ".asm",
699     NULL                        /* no do_assemble function */
700   },
701   {
702     NULL,
703     LINKCMD,
704     NULL,
705     ".o",
706     1
707   },
708   {
709     _gbz80_defaultRules
710   },
711   {
712     /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
713     1, 2, 2, 4, 2, 2, 2, 1, 4, 4
714   },
715   {
716     "XSEG",
717     "STACK",
718     "CODE",
719     "DATA",
720     "ISEG",
721     "XSEG",
722     "BSEG",
723     "RSEG",
724     "GSINIT",
725     "OVERLAY",
726     "GSFINAL",
727     "HOME",
728     NULL, /* xidata */
729     NULL, /* xinit */
730     NULL,
731     NULL,
732     1
733   },
734   { NULL, NULL },
735   {
736     -1, 0, 0, 2, 0, 4
737   },
738     /* gbZ80 has no native mul/div commands */
739   {
740     0, 2
741   },
742   {
743     z80_emitDebuggerSymbol
744   },
745   {
746     255,        /* maxCount */
747     3,          /* sizeofElement */
748     /* The rest of these costs are bogus. They approximate */
749     /* the behavior of src/SDCCicode.c 1.207 and earlier.  */
750     {4,4,4},    /* sizeofMatchJump[] */
751     {0,0,0},    /* sizeofRangeCompare[] */
752     0,          /* sizeofSubtract */
753     3,          /* sizeofDispatch */
754   },
755   "_",
756   _gbz80_init,
757   _parseOptions,
758   _gbz80_options,
759   NULL,
760   _finaliseOptions,
761   _setDefaultOptions,
762   z80_assignRegisters,
763   _getRegName,
764   _keywords,
765   0,                            /* no assembler preamble */
766   NULL,                         /* no genAssemblerEnd */
767   0,                            /* no local IVT generation code */
768   0,                            /* no genXINIT code */
769   NULL,                         /* genInitStartup */
770   _reset_regparm,
771   _reg_parm,
772   _process_pragma,
773   _mangleSupportFunctionName,
774   _hasNativeMulFor,
775   hasExtBitOp,                  /* hasExtBitOp */
776   oclsExpense,                  /* oclsExpense */
777   TRUE,
778   TRUE,                         /* little endian */
779   0,                            /* leave lt */
780   0,                            /* leave gt */
781   1,                            /* transform <= to ! > */
782   1,                            /* transform >= to ! < */
783   1,                            /* transform != to !(a == b) */
784   0,                            /* leave == */
785   TRUE,                         /* Array initializer support. */
786   0,                            /* no CSE cost estimation yet */
787   NULL,                         /* no builtin functions */
788   GPOINTER,                     /* treat unqualified pointers as "generic" pointers */
789   1,                            /* reset labelKey to 1 */
790   1,                            /* globals & local static allowed */
791   PORT_MAGIC
792 };