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