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
88 extern PORT gbz80_port;
93 static builtins _z80_builtins[] = {
95 { "__builtin_strcpy", "v", 2, {"cg*", "cg*" } },
96 { "__builtin_memcpy", "cg*", 3, {"cg*", "cg*", "ui" } },
98 { NULL , NULL,0, {NULL}}
104 z80_opts.sub = SUB_Z80;
105 asm_addTree (&_asxxxx_z80);
111 z80_opts.sub = SUB_GBZ80;
115 _reset_regparm (void)
121 _reg_parm (sym_link * l)
123 if (options.noRegParams)
129 if (_G.regParams == 2)
141 _process_pragma (const char *sz)
143 if( startsWith( sz, "bank=" ) || startsWith( sz, "bank " ))
148 werror(W_DEPRECATED_PRAGMA, "bank=");
150 strncpy (buffer, sz + 5, sizeof (buffer));
151 buffer[sizeof (buffer) - 1 ] = '\0';
153 if (isdigit (buffer[0]))
157 else if (!strcmp (buffer, "BASE"))
159 strcpy (buffer, "HOME");
161 if (isdigit (buffer[0]))
163 /* Arg was a bank number. Handle in an ASM independent
166 strncpy (num, sz + 5, sizeof (num));
167 num[sizeof (num) -1] = '\0';
172 case ASM_TYPE_ASXXXX:
173 sprintf (buffer, "CODE_%s", num);
176 sprintf (buffer, "CODE,BANK[%s]", num);
179 /* PENDING: what to use for ISAS? */
180 sprintf (buffer, "CODE,BANK(%s)", num);
186 gbz80_port.mem.code_name = Safe_strdup (buffer);
187 code->sname = gbz80_port.mem.code_name;
190 else if( startsWith( sz, "portmode=" ) || startsWith( sz, "portmode " ))
191 { /*.p.t.20030716 - adding pragma to manipulate z80 i/o port addressing modes */
195 werror(W_DEPRECATED_PRAGMA, "portmode=");
197 strncpy( bfr, sz + 9, sizeof (bfr));
198 bfr[sizeof (bfr) - 1] = '\0';
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; }
213 static const char *_gbz80_rgbasmCmd[] =
215 "rgbasm", "-o\"$1.o\"", "\"$1.asm\"", NULL
218 static const char *_gbz80_rgblinkCmd[] =
220 "xlink", "-tg", "-n\"$1.sym\"", "-m\"$1.map\"", "-zFF", "\"$1.lnk\"", NULL
224 _gbz80_rgblink (void)
228 /* first we need to create the <filename>.lnk file */
229 sprintf (scratchFileName, "%s.lnk", dstFileName);
230 if (!(lnkfile = fopen (scratchFileName, "w")))
232 werror (E_FILE_OPEN_ERR, scratchFileName);
236 fprintf (lnkfile, "[Objects]\n");
238 fprintf (lnkfile, "%s.o\n", dstFileName);
240 fputStrSet(lnkfile, relFilesSet);
242 fprintf (lnkfile, "\n[Libraries]\n");
243 /* additional libraries if any */
244 fputStrSet(lnkfile, libFilesSet);
246 fprintf (lnkfile, "\n[Output]\n" "%s.gb", dstFileName);
250 buildCmdLine (buffer,port->linker.cmd, dstFileName, NULL, NULL, NULL);
251 /* call the linker */
252 if (my_system (buffer))
254 perror ("Cannot exec linker");
260 _parseOptions (int *pargc, char **argv, int *i)
262 if (argv[*i][0] == '-')
264 if (argv[*i][1] == 'b' && IS_GB)
266 int bank = atoi (argv[*i] + 3);
272 sprintf (buffer, "CODE_%u", bank);
273 gbz80_port.mem.code_name = Safe_strdup (buffer);
277 sprintf (buffer, "DATA_%u", bank);
278 gbz80_port.mem.data_name = Safe_strdup (buffer);
282 else if (!strncmp (argv[*i], "--asm=", 6))
284 if (!strcmp (argv[*i], "--asm=rgbds"))
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;
293 else if (!strcmp (argv[*i], "--asm=asxxxx"))
295 _G.asmType = ASM_TYPE_ASXXXX;
298 else if (!strcmp (argv[*i], "--asm=isas"))
300 asm_addTree (&_isas_gb);
301 /* Munge the function prefix */
302 gbz80_port.fun_prefix = "";
303 _G.asmType = ASM_TYPE_ISAS;
306 else if (!strcmp (argv[*i], "--asm=z80asm"))
308 port->assembler.externGlobal = TRUE;
309 asm_addTree (&_z80asm_z80);
310 _G.asmType = ASM_TYPE_ISAS;
314 else if (!strncmp (argv[*i], "--portmode=", 11))
316 if (!strcmp (argv[*i], "--portmode=z80"))
318 z80_opts.port_mode = 80;
321 else if (!strcmp (argv[*i], "--portmode=z180"))
323 z80_opts.port_mode = 180;
336 if (options.nostdlib == FALSE)
342 dbuf_init(&dbuf, PATH_MAX);
344 for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
346 buildCmdLine2(path, sizeof path, "-k\"%s" DIR_SEPARATOR_STRING "{port}\" ", s);
347 dbuf_append(&dbuf, path, strlen(path));
349 buildCmdLine2(path, sizeof path, "-l\"{port}.lib\"", s);
350 dbuf_append(&dbuf, path, strlen(path));
352 setMainValue ("z80libspec", dbuf_c_str(&dbuf));
355 for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
357 struct stat stat_buf;
359 buildCmdLine2(path, sizeof path, "%s" DIR_SEPARATOR_STRING "{port}" DIR_SEPARATOR_STRING "crt0{objext}", s);
360 if (stat(path, &stat_buf) == 0)
365 setMainValue ("z80crt0", "\"crt0{objext}\"");
369 size_t len = strlen(path) + 3;
371 buf = Safe_alloc(len);
372 SNPRINTF(buf, len, "\"%s\"", path);
373 setMainValue("z80crt0", buf);
379 setMainValue ("z80libspec", "");
380 setMainValue ("z80crt0", "");
383 setMainValue ("z80extralibfiles", (s = joinStrSet(libFilesSet)));
384 Safe_free((void *)s);
385 setMainValue ("z80extralibpaths", (s = joinStrSet(libPathsSet)));
386 Safe_free((void *)s);
390 setMainValue ("z80outputtypeflag", "-z");
391 setMainValue ("z80outext", ".gb");
395 setMainValue ("z80outputtypeflag", "-i");
396 setMainValue ("z80outext", ".ihx");
399 setMainValue ("stdobjdstfilename" , "{dstfilename}{objext}");
400 setMainValue ("stdlinkdstfilename", "{dstfilename}{z80outext}");
402 setMainValue ("z80extraobj", (s = joinStrSet(relFilesSet)));
403 Safe_free((void *)s);
405 sprintf (buffer, "-b_CODE=0x%04X -b_DATA=0x%04X", options.code_loc, options.data_loc);
406 setMainValue ("z80bases", buffer);
410 _finaliseOptions (void)
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);
421 _setDefaultOptions (void)
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;
435 options.data_loc = 0xC000;
439 options.data_loc = 0x8000;
442 optimize.global_cse = 1;
447 optimize.loopInvariant = 1;
448 optimize.loopInduction = 1;
454 policy is the function policy
455 params is the parameter format
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
464 rr - reentrant, caller saves
466 A combination of register short names and s to signify stack variables.
468 bds - first two args appear in BC and DE, the rest on the stack
469 s - all arguments are on the stack.
472 _mangleSupportFunctionName(char *original)
476 sprintf(buffer, "%s_rr%s_%s", original,
477 options.profile ? "f" : "x",
478 options.noRegParams ? "s" : "bds"
481 return Safe_strdup(buffer);
485 _getRegName (struct regs *reg)
496 _hasNativeMulFor (iCode *ic, sym_link *left, sym_link *right)
498 sym_link *test = NULL;
506 if ( IS_LITERAL (left))
509 val = OP_VALUE (IC_LEFT (ic));
511 else if ( IS_LITERAL (right))
514 val = OP_VALUE (IC_RIGHT (ic));
521 if ( getSize (test) <= 2)
529 /* Indicate which extended bit operations this port supports */
531 hasExtBitOp (int op, int size)
539 /* Indicate the expense of an access to an output storage class */
541 oclsExpense (struct memmap *oclass)
543 if (IN_FARSPACE(oclass))
550 #define LINKCMD "link-{port} -nf {dstfilename}"
553 "link-{port} -n -c -- {z80bases} -m -j" \
555 " {z80extralibfiles} {z80extralibpaths}" \
556 " {z80outputtypeflag} \"{linkdstfilename}\"" \
558 " \"{dstfilename}{objext}\"" \
563 "as-{port} -plosgff \"{objdstfilename}\" \"{dstfilename}{asmext}\""
570 "Zilog Z80", /* Target name */
571 NULL, /* Processor name */
575 MODEL_MEDIUM | MODEL_SMALL,
581 "-plosgff", /* Options with debug */
582 "-plosgff", /* Options without debug */
597 /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
598 1, 2, 2, 4, 2, 2, 2, 1, 4, 4
624 /* Z80 has no native mul/div commands */
629 z80_emitDebuggerSymbol
633 3, /* sizeofElement */
634 /* The rest of these costs are bogus. They approximate */
635 /* the behavior of src/SDCCicode.c 1.207 and earlier. */
636 {4,4,4}, /* sizeofMatchJump[] */
637 {0,0,0}, /* sizeofRangeCompare[] */
638 0, /* sizeofSubtract */
639 3, /* sizeofDispatch */
651 0, /* no assembler preamble */
652 NULL, /* no genAssemblerEnd */
653 0, /* no local IVT generation code */
654 0, /* no genXINIT code */
655 NULL, /* genInitStartup */
659 _mangleSupportFunctionName,
661 hasExtBitOp, /* hasExtBitOp */
662 oclsExpense, /* oclsExpense */
664 TRUE, /* little endian */
667 1, /* transform <= to ! > */
668 1, /* transform >= to ! < */
669 1, /* transform != to !(a == b) */
671 TRUE, /* Array initializer support. */
672 0, /* no CSE cost estimation yet */
673 _z80_builtins, /* no builtin functions */
674 GPOINTER, /* treat unqualified pointers as "generic" pointers */
675 1, /* reset labelKey to 1 */
676 1, /* globals & local static allowed */
685 "Gameboy Z80-like", /* Target name */
690 MODEL_MEDIUM | MODEL_SMALL,
696 "-plosgff", /* Options with debug */
697 "-plosgff", /* Options without debug */
700 NULL /* no do_assemble function */
713 /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
714 1, 2, 2, 4, 2, 2, 2, 1, 4, 4
740 /* gbZ80 has no native mul/div commands */
745 z80_emitDebuggerSymbol
749 3, /* sizeofElement */
750 /* The rest of these costs are bogus. They approximate */
751 /* the behavior of src/SDCCicode.c 1.207 and earlier. */
752 {4,4,4}, /* sizeofMatchJump[] */
753 {0,0,0}, /* sizeofRangeCompare[] */
754 0, /* sizeofSubtract */
755 3, /* sizeofDispatch */
767 0, /* no assembler preamble */
768 NULL, /* no genAssemblerEnd */
769 0, /* no local IVT generation code */
770 0, /* no genXINIT code */
771 NULL, /* genInitStartup */
775 _mangleSupportFunctionName,
777 hasExtBitOp, /* hasExtBitOp */
778 oclsExpense, /* oclsExpense */
780 TRUE, /* little endian */
783 1, /* transform <= to ! > */
784 1, /* transform >= to ! < */
785 1, /* transform != to !(a == b) */
787 TRUE, /* Array initializer support. */
788 0, /* no CSE cost estimation yet */
789 NULL, /* no builtin functions */
790 GPOINTER, /* treat unqualified pointers as "generic" pointers */
791 1, /* reset labelKey to 1 */
792 1, /* globals & local static allowed */