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
87 extern PORT gbz80_port;
92 static builtins _z80_builtins[] = {
94 { "__builtin_strcpy", "v", 2, {"cg*", "cg*" } },
95 { "__builtin_memcpy", "cg*", 3, {"cg*", "cg*", "ui" } },
97 { NULL , NULL,0, {NULL}}
103 z80_opts.sub = SUB_Z80;
104 asm_addTree (&_asxxxx_z80);
110 z80_opts.sub = SUB_GBZ80;
120 _reg_parm (sym_link * l)
122 if (options.noRegParams)
128 if (_G.regParams == 2)
140 _process_pragma (const char *sz)
142 if( startsWith( sz, "bank=" ) || startsWith( sz, "bank " ))
147 werror(W_DEPRECATED_PRAGMA, "bank=");
149 strncpy (buffer, sz + 5, sizeof (buffer));
150 buffer[sizeof (buffer) - 1 ] = '\0';
152 if (isdigit (buffer[0]))
156 else if (!strcmp (buffer, "BASE"))
158 strcpy (buffer, "HOME");
160 if (isdigit (buffer[0]))
162 /* Arg was a bank number. Handle in an ASM independent
165 strncpy (num, sz + 5, sizeof (num));
166 num[sizeof (num) -1] = '\0';
171 case ASM_TYPE_ASXXXX:
172 sprintf (buffer, "CODE_%s", num);
175 sprintf (buffer, "CODE,BANK[%s]", num);
178 /* PENDING: what to use for ISAS? */
179 sprintf (buffer, "CODE,BANK(%s)", num);
185 gbz80_port.mem.code_name = Safe_strdup (buffer);
186 code->sname = gbz80_port.mem.code_name;
189 else if( startsWith( sz, "portmode=" ) || startsWith( sz, "portmode " ))
190 { /*.p.t.20030716 - adding pragma to manipulate z80 i/o port addressing modes */
194 werror(W_DEPRECATED_PRAGMA, "portmode=");
196 strncpy( bfr, sz + 9, sizeof (bfr));
197 bfr[sizeof (bfr) - 1] = '\0';
200 if ( !strcmp( bfr, "z80" )){ z80_opts.port_mode = 80; }
201 else if( !strcmp( bfr, "z180" )){ z80_opts.port_mode = 180; }
202 else if( !strcmp( bfr, "save" )){ z80_opts.port_back = z80_opts.port_mode; }
203 else if( !strcmp( bfr, "restore" )){ z80_opts.port_mode = z80_opts.port_back; }
212 static const char *_gbz80_rgbasmCmd[] =
214 "rgbasm", "-o\"$1.o\"", "\"$1.asm\"", NULL
217 static const char *_gbz80_rgblinkCmd[] =
219 "xlink", "-tg", "-n\"$1.sym\"", "-m\"$1.map\"", "-zFF", "\"$1.lnk\"", NULL
223 _gbz80_rgblink (void)
227 /* first we need to create the <filename>.lnk file */
228 sprintf (scratchFileName, "%s.lnk", dstFileName);
229 if (!(lnkfile = fopen (scratchFileName, "w")))
231 werror (E_FILE_OPEN_ERR, scratchFileName);
235 fprintf (lnkfile, "[Objects]\n");
237 fprintf (lnkfile, "%s.o\n", dstFileName);
239 fputStrSet(lnkfile, relFilesSet);
241 fprintf (lnkfile, "\n[Libraries]\n");
242 /* additional libraries if any */
243 fputStrSet(lnkfile, libFilesSet);
245 fprintf (lnkfile, "\n[Output]\n" "%s.gb", dstFileName);
249 buildCmdLine (buffer,port->linker.cmd, dstFileName, NULL, NULL, NULL);
250 /* call the linker */
251 if (my_system (buffer))
253 perror ("Cannot exec linker");
259 _parseOptions (int *pargc, char **argv, int *i)
261 if (argv[*i][0] == '-')
263 if (argv[*i][1] == 'b' && IS_GB)
265 int bank = atoi (argv[*i] + 3);
271 sprintf (buffer, "CODE_%u", bank);
272 gbz80_port.mem.code_name = Safe_strdup (buffer);
276 sprintf (buffer, "DATA_%u", bank);
277 gbz80_port.mem.data_name = Safe_strdup (buffer);
281 else if (!strncmp (argv[*i], "--asm=", 6))
283 if (!strcmp (argv[*i], "--asm=rgbds"))
285 asm_addTree (&_rgbds_gb);
286 gbz80_port.assembler.cmd = _gbz80_rgbasmCmd;
287 gbz80_port.linker.cmd = _gbz80_rgblinkCmd;
288 gbz80_port.linker.do_link = _gbz80_rgblink;
289 _G.asmType = ASM_TYPE_RGBDS;
292 else if (!strcmp (argv[*i], "--asm=asxxxx"))
294 _G.asmType = ASM_TYPE_ASXXXX;
297 else if (!strcmp (argv[*i], "--asm=isas"))
299 asm_addTree (&_isas_gb);
300 /* Munge the function prefix */
301 gbz80_port.fun_prefix = "";
302 _G.asmType = ASM_TYPE_ISAS;
305 else if (!strcmp (argv[*i], "--asm=z80asm"))
307 port->assembler.externGlobal = TRUE;
308 asm_addTree (&_z80asm_z80);
309 _G.asmType = ASM_TYPE_ISAS;
313 else if (!strncmp (argv[*i], "--portmode=", 11))
315 if (!strcmp (argv[*i], "--portmode=z80"))
317 z80_opts.port_mode = 80;
320 else if (!strcmp (argv[*i], "--portmode=z180"))
322 z80_opts.port_mode = 180;
335 if (options.nostdlib == FALSE)
341 dbuf_init(&dbuf, PATH_MAX);
343 for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
345 buildCmdLine2(path, sizeof path, "-k\"%s" DIR_SEPARATOR_STRING "{port}\" ", s);
346 dbuf_append(&dbuf, path, strlen(path));
348 buildCmdLine2(path, sizeof path, "-l\"{port}.lib\"", s);
349 dbuf_append(&dbuf, path, strlen(path));
351 setMainValue ("z80libspec", dbuf_c_str(&dbuf));
354 for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
356 struct stat stat_buf;
358 buildCmdLine2(path, sizeof path, "%s" DIR_SEPARATOR_STRING "{port}" DIR_SEPARATOR_STRING "crt0{objext}", s);
359 if (stat(path, &stat_buf) == 0)
364 setMainValue ("z80crt0", "\"crt0{objext}\"");
368 size_t len = strlen(path) + 3;
370 buf = Safe_alloc(len);
371 SNPRINTF(buf, len, "\"%s\"", path);
372 setMainValue("z80crt0", buf);
378 setMainValue ("z80libspec", "");
379 setMainValue ("z80crt0", "");
382 setMainValue ("z80extralibfiles", (s = joinStrSet(libFilesSet)));
383 Safe_free((void *)s);
384 setMainValue ("z80extralibpaths", (s = joinStrSet(libPathsSet)));
385 Safe_free((void *)s);
389 setMainValue ("z80outputtypeflag", "-z");
390 setMainValue ("z80outext", ".gb");
394 setMainValue ("z80outputtypeflag", "-i");
395 setMainValue ("z80outext", ".ihx");
398 setMainValue ("stdobjdstfilename" , "{dstfilename}{objext}");
399 setMainValue ("stdlinkdstfilename", "{dstfilename}{z80outext}");
401 setMainValue ("z80extraobj", (s = joinStrSet(relFilesSet)));
402 Safe_free((void *)s);
404 sprintf (buffer, "-b_CODE=0x%04X -b_DATA=0x%04X", options.code_loc, options.data_loc);
405 setMainValue ("z80bases", buffer);
409 _finaliseOptions (void)
411 port->mem.default_local_map = data;
412 port->mem.default_globl_map = data;
413 if (_G.asmType == ASM_TYPE_ASXXXX && IS_GB)
414 asm_addTree (&_asxxxx_gb);
420 _setDefaultOptions (void)
423 options.stackAuto = 1;
424 options.mainreturn = 1;
425 /* first the options part */
426 options.intlong_rent = 1;
427 options.float_rent = 1;
428 options.noRegParams = 1;
429 /* Default code and data locations. */
430 options.code_loc = 0x200;
434 options.data_loc = 0xC000;
438 options.data_loc = 0x8000;
441 optimize.global_cse = 1;
446 optimize.loopInvariant = 1;
447 optimize.loopInduction = 1;
453 policy is the function policy
454 params is the parameter format
459 r is 'r' for reentrant, 's' for static functions
460 s is 'c' for callee saves, 'r' for caller saves
461 p is 'p' for profiling on, 'x' for profiling off
463 rr - reentrant, caller saves
465 A combination of register short names and s to signify stack variables.
467 bds - first two args appear in BC and DE, the rest on the stack
468 s - all arguments are on the stack.
471 _mangleSupportFunctionName(char *original)
475 sprintf(buffer, "%s_rr%s_%s", original,
476 options.profile ? "f" : "x",
477 options.noRegParams ? "s" : "bds"
480 return Safe_strdup(buffer);
484 _getRegName (struct regs *reg)
495 _hasNativeMulFor (iCode *ic, sym_link *left, sym_link *right)
497 sym_link *test = NULL;
505 if ( IS_LITERAL (left))
508 val = OP_VALUE (IC_LEFT (ic));
510 else if ( IS_LITERAL (right))
513 val = OP_VALUE (IC_RIGHT (ic));
520 if ( getSize (test) <= 2)
528 /* Indicate which extended bit operations this port supports */
530 hasExtBitOp (int op, int size)
538 /* Indicate the expense of an access to an output storage class */
540 oclsExpense (struct memmap *oclass)
542 if (IN_FARSPACE(oclass))
549 #define LINKCMD "link-{port} -nf {dstfilename}"
552 "link-{port} -n -c -- {z80bases} -m -j" \
554 " {z80extralibfiles} {z80extralibpaths}" \
555 " {z80outputtypeflag} \"{linkdstfilename}\"" \
557 " \"{dstfilename}{objext}\"" \
562 "as-{port} -plosgff \"{objdstfilename}\" \"{dstfilename}{asmext}\""
569 "Zilog Z80", /* Target name */
570 NULL, /* Processor name */
574 MODEL_MEDIUM | MODEL_SMALL,
580 "-plosgff", /* Options with debug */
581 "-plosgff", /* Options without debug */
596 /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
597 1, 2, 2, 4, 2, 2, 2, 1, 4, 4
622 /* Z80 has no native mul/div commands */
627 z80_emitDebuggerSymbol
638 0, /* no assembler preamble */
639 NULL, /* no genAssemblerEnd */
640 0, /* no local IVT generation code */
641 0, /* no genXINIT code */
642 NULL, /* genInitStartup */
646 _mangleSupportFunctionName,
648 hasExtBitOp, /* hasExtBitOp */
649 oclsExpense, /* oclsExpense */
651 TRUE, /* little endian */
654 1, /* transform <= to ! > */
655 1, /* transform >= to ! < */
656 1, /* transform != to !(a == b) */
658 TRUE, /* Array initializer support. */
659 0, /* no CSE cost estimation yet */
660 _z80_builtins, /* no builtin functions */
661 GPOINTER, /* treat unqualified pointers as "generic" pointers */
662 1, /* reset labelKey to 1 */
663 1, /* globals & local static allowed */
672 "Gameboy Z80-like", /* Target name */
677 MODEL_MEDIUM | MODEL_SMALL,
683 "-plosgff", /* Options with debug */
684 "-plosgff", /* Options without debug */
687 NULL /* no do_assemble function */
700 /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
701 1, 2, 2, 4, 2, 2, 2, 1, 4, 4
726 /* gbZ80 has no native mul/div commands */
731 z80_emitDebuggerSymbol
742 0, /* no assembler preamble */
743 NULL, /* no genAssemblerEnd */
744 0, /* no local IVT generation code */
745 0, /* no genXINIT code */
746 NULL, /* genInitStartup */
750 _mangleSupportFunctionName,
752 hasExtBitOp, /* hasExtBitOp */
753 oclsExpense, /* oclsExpense */
755 TRUE, /* little endian */
758 1, /* transform <= to ! > */
759 1, /* transform >= to ! < */
760 1, /* transform != to !(a == b) */
762 TRUE, /* Array initializer support. */
763 0, /* no CSE cost estimation yet */
764 NULL, /* no builtin functions */
765 GPOINTER, /* treat unqualified pointers as "generic" pointers */
766 1, /* reset labelKey to 1 */
767 1, /* globals & local static allowed */