1 /*-------------------------------------------------------------------------
2 main.c - Z80 specific definitions.
4 Michael Hope <michaelh@juju.net.nz> 2001
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
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.
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.
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 -------------------------------------------------------------------------*/
32 static char _z80_defaultRules[] =
35 #include "peeph-z80.rul"
38 static char _gbz80_defaultRules[] =
41 #include "peeph-gbz80.rul"
46 static OPTION _z80_options[] =
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)" },
53 static OPTION _gbz80_options[] =
55 { 0, "--callee-saves-bc", &z80_opts.calleeSavesBC, "Force a called function to always save BC" },
72 /* determine if we can register a parameter */
77 static char *_keywords[] =
82 "at", //.p.t.20030714 adding support for 'sfr at ADDR' construct
83 "_naked", //.p.t.20030714 adding support for '_naked' functions
89 extern PORT gbz80_port;
94 static builtins _z80_builtins[] = {
96 { "__builtin_strcpy", "v", 2, {"cg*", "cg*" } },
97 { "__builtin_memcpy", "cg*", 3, {"cg*", "cg*", "ui" } },
99 { NULL , NULL,0, {NULL}}
105 z80_opts.sub = SUB_Z80;
106 asm_addTree (&_asxxxx_z80);
112 z80_opts.sub = SUB_GBZ80;
116 _reset_regparm (void)
122 _reg_parm (sym_link * l, bool reentrant)
124 if (options.noRegParams)
130 if (_G.regParams == 2)
142 _process_pragma (const char *sz)
144 if( startsWith( sz, "bank=" ) || startsWith( sz, "bank " ))
149 werror(W_DEPRECATED_PRAGMA, "bank=");
151 strncpy (buffer, sz + 5, sizeof (buffer));
152 buffer[sizeof (buffer) - 1 ] = '\0';
154 if (isdigit ((unsigned char)buffer[0]))
158 else if (!strcmp (buffer, "BASE"))
160 strcpy (buffer, "HOME");
162 if (isdigit ((unsigned char)buffer[0]))
164 /* Arg was a bank number. Handle in an ASM independent
167 strncpy (num, sz + 5, sizeof (num));
168 num[sizeof (num) -1] = '\0';
173 case ASM_TYPE_ASXXXX:
174 sprintf (buffer, "CODE_%s", num);
177 sprintf (buffer, "CODE,BANK[%s]", num);
180 /* PENDING: what to use for ISAS? */
181 sprintf (buffer, "CODE,BANK(%s)", num);
187 gbz80_port.mem.code_name = Safe_strdup (buffer);
188 code->sname = gbz80_port.mem.code_name;
191 else if( startsWith( sz, "portmode=" ) || startsWith( sz, "portmode " ))
192 { /*.p.t.20030716 - adding pragma to manipulate z80 i/o port addressing modes */
196 werror(W_DEPRECATED_PRAGMA, "portmode=");
198 strncpy( bfr, sz + 9, sizeof (bfr));
199 bfr[sizeof (bfr) - 1] = '\0';
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; }
214 static const char *_gbz80_rgbasmCmd[] =
216 "rgbasm", "-o\"$1.o\"", "\"$1.asm\"", NULL
219 static const char *_gbz80_rgblinkCmd[] =
221 "xlink", "-tg", "-n\"$1.sym\"", "-m\"$1.map\"", "-zFF", "\"$1.lnk\"", NULL
225 _gbz80_rgblink (void)
229 /* first we need to create the <filename>.lnk file */
230 sprintf (scratchFileName, "%s.lnk", dstFileName);
231 if (!(lnkfile = fopen (scratchFileName, "w")))
233 werror (E_FILE_OPEN_ERR, scratchFileName);
237 fprintf (lnkfile, "[Objects]\n");
239 fprintf (lnkfile, "%s.o\n", dstFileName);
241 fputStrSet(lnkfile, relFilesSet);
243 fprintf (lnkfile, "\n[Libraries]\n");
244 /* additional libraries if any */
245 fputStrSet(lnkfile, libFilesSet);
247 fprintf (lnkfile, "\n[Output]\n" "%s.gb", dstFileName);
251 buildCmdLine (buffer,port->linker.cmd, dstFileName, NULL, NULL, NULL);
252 /* call the linker */
253 if (my_system (buffer))
255 perror ("Cannot exec linker");
261 _parseOptions (int *pargc, char **argv, int *i)
263 if (argv[*i][0] == '-')
265 if (argv[*i][1] == 'b' && IS_GB)
267 int bank = atoi (argv[*i] + 3);
273 sprintf (buffer, "CODE_%u", bank);
274 gbz80_port.mem.code_name = Safe_strdup (buffer);
278 sprintf (buffer, "DATA_%u", bank);
279 gbz80_port.mem.data_name = Safe_strdup (buffer);
283 else if (!strncmp (argv[*i], "--asm=", 6))
285 if (!strcmp (argv[*i], "--asm=rgbds"))
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;
294 else if (!strcmp (argv[*i], "--asm=asxxxx"))
296 _G.asmType = ASM_TYPE_ASXXXX;
299 else if (!strcmp (argv[*i], "--asm=isas"))
301 asm_addTree (&_isas_gb);
302 /* Munge the function prefix */
303 gbz80_port.fun_prefix = "";
304 _G.asmType = ASM_TYPE_ISAS;
307 else if (!strcmp (argv[*i], "--asm=z80asm"))
309 port->assembler.externGlobal = TRUE;
310 asm_addTree (&_z80asm_z80);
311 _G.asmType = ASM_TYPE_ISAS;
315 else if (!strncmp (argv[*i], "--portmode=", 11))
317 if (!strcmp (argv[*i], "--portmode=z80"))
319 z80_opts.port_mode = 80;
322 else if (!strcmp (argv[*i], "--portmode=z180"))
324 z80_opts.port_mode = 180;
337 if (options.nostdlib == FALSE)
343 dbuf_init(&dbuf, PATH_MAX);
345 for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
347 buildCmdLine2(path, sizeof path, "-k\"%s" DIR_SEPARATOR_STRING "{port}\" ", s);
348 dbuf_append(&dbuf, path, strlen(path));
350 buildCmdLine2(path, sizeof path, "-l\"{port}.lib\"", s);
351 dbuf_append(&dbuf, path, strlen(path));
353 setMainValue ("z80libspec", dbuf_c_str(&dbuf));
356 for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
358 struct stat stat_buf;
360 buildCmdLine2(path, sizeof path, "%s" DIR_SEPARATOR_STRING "{port}" DIR_SEPARATOR_STRING "crt0{objext}", s);
361 if (stat(path, &stat_buf) == 0)
366 setMainValue ("z80crt0", "\"crt0{objext}\"");
370 size_t len = strlen(path) + 3;
372 buf = Safe_alloc(len);
373 SNPRINTF(buf, len, "\"%s\"", path);
374 setMainValue("z80crt0", buf);
380 setMainValue ("z80libspec", "");
381 setMainValue ("z80crt0", "");
384 setMainValue ("z80extralibfiles", (s = joinStrSet(libFilesSet)));
385 Safe_free((void *)s);
386 setMainValue ("z80extralibpaths", (s = joinStrSet(libPathsSet)));
387 Safe_free((void *)s);
391 setMainValue ("z80outputtypeflag", "-z");
392 setMainValue ("z80outext", ".gb");
396 setMainValue ("z80outputtypeflag", "-i");
397 setMainValue ("z80outext", ".ihx");
400 setMainValue ("stdobjdstfilename" , "{dstfilename}{objext}");
401 setMainValue ("stdlinkdstfilename", "{dstfilename}{z80outext}");
403 setMainValue ("z80extraobj", (s = joinStrSet(relFilesSet)));
404 Safe_free((void *)s);
406 sprintf (buffer, "-b_CODE=0x%04X -b_DATA=0x%04X", options.code_loc, options.data_loc);
407 setMainValue ("z80bases", buffer);
411 _finaliseOptions (void)
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);
422 _setDefaultOptions (void)
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;
436 options.data_loc = 0xC000;
440 options.data_loc = 0x8000;
443 optimize.global_cse = 1;
448 optimize.loopInvariant = 1;
449 optimize.loopInduction = 1;
455 policy is the function policy
456 params is the parameter format
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
465 rr - reentrant, caller saves
467 A combination of register short names and s to signify stack variables.
469 bds - first two args appear in BC and DE, the rest on the stack
470 s - all arguments are on the stack.
473 _mangleSupportFunctionName(char *original)
477 sprintf(buffer, "%s_rr%s_%s", original,
478 options.profile ? "f" : "x",
479 options.noRegParams ? "s" : "bds"
482 return Safe_strdup(buffer);
486 _getRegName (struct regs *reg)
497 _hasNativeMulFor (iCode *ic, sym_link *left, sym_link *right)
499 sym_link *test = NULL;
507 if ( IS_LITERAL (left))
510 val = OP_VALUE (IC_LEFT (ic));
512 else if ( IS_LITERAL (right))
515 val = OP_VALUE (IC_RIGHT (ic));
522 if ( getSize (test) <= 2)
530 /* Indicate which extended bit operations this port supports */
532 hasExtBitOp (int op, int size)
540 /* Indicate the expense of an access to an output storage class */
542 oclsExpense (struct memmap *oclass)
544 if (IN_FARSPACE(oclass))
551 #define LINKCMD "link-{port} -nf {dstfilename}"
554 "link-{port} -n -c -- {z80bases} -m -j" \
556 " {z80extralibfiles} {z80extralibpaths}" \
557 " {z80outputtypeflag} \"{linkdstfilename}\"" \
559 " \"{dstfilename}{objext}\"" \
564 "as-{port} -plosgff \"{objdstfilename}\" \"{dstfilename}{asmext}\""
571 "Zilog Z80", /* Target name */
572 NULL, /* Processor name */
576 MODEL_MEDIUM | MODEL_SMALL,
582 "-plosgff", /* Options with debug */
583 "-plosgff", /* Options without debug */
598 /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
599 1, 2, 2, 4, 2, 2, 2, 1, 4, 4
617 NULL, /* const_name */
626 /* Z80 has no native mul/div commands */
631 z80_emitDebuggerSymbol
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 */
653 0, /* no assembler preamble */
654 NULL, /* no genAssemblerEnd */
655 0, /* no local IVT generation code */
656 0, /* no genXINIT code */
657 NULL, /* genInitStartup */
661 _mangleSupportFunctionName,
663 hasExtBitOp, /* hasExtBitOp */
664 oclsExpense, /* oclsExpense */
666 TRUE, /* little endian */
669 1, /* transform <= to ! > */
670 1, /* transform >= to ! < */
671 1, /* transform != to !(a == b) */
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 */
687 "Gameboy Z80-like", /* Target name */
692 MODEL_MEDIUM | MODEL_SMALL,
698 "-plosgff", /* Options with debug */
699 "-plosgff", /* Options without debug */
702 NULL /* no do_assemble function */
715 /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
716 1, 2, 2, 4, 2, 2, 2, 1, 4, 4
734 NULL, /* const_name */
743 /* gbZ80 has no native mul/div commands */
748 z80_emitDebuggerSymbol
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 */
770 0, /* no assembler preamble */
771 NULL, /* no genAssemblerEnd */
772 0, /* no local IVT generation code */
773 0, /* no genXINIT code */
774 NULL, /* genInitStartup */
778 _mangleSupportFunctionName,
780 hasExtBitOp, /* hasExtBitOp */
781 oclsExpense, /* oclsExpense */
783 TRUE, /* little endian */
786 1, /* transform <= to ! > */
787 1, /* transform >= to ! < */
788 1, /* transform != to !(a == b) */
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 */