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;
189 options.code_seg = gbz80_port.mem.code_name;
192 else if( startsWith( sz, "portmode=" ) || startsWith( sz, "portmode " ))
193 { /*.p.t.20030716 - adding pragma to manipulate z80 i/o port addressing modes */
197 werror(W_DEPRECATED_PRAGMA, "portmode=");
199 strncpy( bfr, sz + 9, sizeof (bfr));
200 bfr[sizeof (bfr) - 1] = '\0';
203 if ( !strcmp( bfr, "z80" )){ z80_opts.port_mode = 80; }
204 else if( !strcmp( bfr, "z180" )){ z80_opts.port_mode = 180; }
205 else if( !strcmp( bfr, "save" )){ z80_opts.port_back = z80_opts.port_mode; }
206 else if( !strcmp( bfr, "restore" )){ z80_opts.port_mode = z80_opts.port_back; }
215 static const char *_gbz80_rgbasmCmd[] =
217 "rgbasm", "-o\"$1.o\"", "\"$1.asm\"", NULL
220 static const char *_gbz80_rgblinkCmd[] =
222 "xlink", "-tg", "-n\"$1.sym\"", "-m\"$1.map\"", "-zFF", "\"$1.lnk\"", NULL
226 _gbz80_rgblink (void)
230 /* first we need to create the <filename>.lnk file */
231 sprintf (scratchFileName, "%s.lnk", dstFileName);
232 if (!(lnkfile = fopen (scratchFileName, "w")))
234 werror (E_FILE_OPEN_ERR, scratchFileName);
238 fprintf (lnkfile, "[Objects]\n");
240 fprintf (lnkfile, "%s.o\n", dstFileName);
242 fputStrSet(lnkfile, relFilesSet);
244 fprintf (lnkfile, "\n[Libraries]\n");
245 /* additional libraries if any */
246 fputStrSet(lnkfile, libFilesSet);
248 fprintf (lnkfile, "\n[Output]\n" "%s.gb", dstFileName);
252 buildCmdLine (buffer,port->linker.cmd, dstFileName, NULL, NULL, NULL);
253 /* call the linker */
254 if (my_system (buffer))
256 perror ("Cannot exec linker");
262 _parseOptions (int *pargc, char **argv, int *i)
264 if (argv[*i][0] == '-')
266 if (argv[*i][1] == 'b' && IS_GB)
268 int bank = atoi (argv[*i] + 3);
274 sprintf (buffer, "CODE_%u", bank);
275 gbz80_port.mem.code_name = Safe_strdup (buffer);
276 options.code_seg = gbz80_port.mem.code_name;
280 sprintf (buffer, "DATA_%u", bank);
281 gbz80_port.mem.data_name = Safe_strdup (buffer);
285 else if (!strncmp (argv[*i], "--asm=", 6))
287 if (!strcmp (argv[*i], "--asm=rgbds"))
289 asm_addTree (&_rgbds_gb);
290 gbz80_port.assembler.cmd = _gbz80_rgbasmCmd;
291 gbz80_port.linker.cmd = _gbz80_rgblinkCmd;
292 gbz80_port.linker.do_link = _gbz80_rgblink;
293 _G.asmType = ASM_TYPE_RGBDS;
296 else if (!strcmp (argv[*i], "--asm=asxxxx"))
298 _G.asmType = ASM_TYPE_ASXXXX;
301 else if (!strcmp (argv[*i], "--asm=isas"))
303 asm_addTree (&_isas_gb);
304 /* Munge the function prefix */
305 gbz80_port.fun_prefix = "";
306 _G.asmType = ASM_TYPE_ISAS;
309 else if (!strcmp (argv[*i], "--asm=z80asm"))
311 port->assembler.externGlobal = TRUE;
312 asm_addTree (&_z80asm_z80);
313 _G.asmType = ASM_TYPE_ISAS;
317 else if (!strncmp (argv[*i], "--portmode=", 11))
319 if (!strcmp (argv[*i], "--portmode=z80"))
321 z80_opts.port_mode = 80;
324 else if (!strcmp (argv[*i], "--portmode=z180"))
326 z80_opts.port_mode = 180;
339 if (options.nostdlib == FALSE)
345 dbuf_init(&dbuf, PATH_MAX);
347 for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
349 buildCmdLine2(path, sizeof path, "-k\"%s" DIR_SEPARATOR_STRING "{port}\" ", s);
350 dbuf_append(&dbuf, path, strlen(path));
352 buildCmdLine2(path, sizeof path, "-l\"{port}.lib\"", s);
353 dbuf_append(&dbuf, path, strlen(path));
355 setMainValue ("z80libspec", dbuf_c_str(&dbuf));
358 for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
360 struct stat stat_buf;
362 buildCmdLine2(path, sizeof path, "%s" DIR_SEPARATOR_STRING "{port}" DIR_SEPARATOR_STRING "crt0{objext}", s);
363 if (stat(path, &stat_buf) == 0)
368 setMainValue ("z80crt0", "\"crt0{objext}\"");
372 size_t len = strlen(path) + 3;
374 buf = Safe_alloc(len);
375 SNPRINTF(buf, len, "\"%s\"", path);
376 setMainValue("z80crt0", buf);
382 setMainValue ("z80libspec", "");
383 setMainValue ("z80crt0", "");
386 setMainValue ("z80extralibfiles", (s = joinStrSet(libFilesSet)));
387 Safe_free((void *)s);
388 setMainValue ("z80extralibpaths", (s = joinStrSet(libPathsSet)));
389 Safe_free((void *)s);
393 setMainValue ("z80outputtypeflag", "-z");
394 setMainValue ("z80outext", ".gb");
398 setMainValue ("z80outputtypeflag", "-i");
399 setMainValue ("z80outext", ".ihx");
402 setMainValue ("stdobjdstfilename" , "{dstfilename}{objext}");
403 setMainValue ("stdlinkdstfilename", "{dstfilename}{z80outext}");
405 setMainValue ("z80extraobj", (s = joinStrSet(relFilesSet)));
406 Safe_free((void *)s);
408 sprintf (buffer, "-b_CODE=0x%04X -b_DATA=0x%04X", options.code_loc, options.data_loc);
409 setMainValue ("z80bases", buffer);
413 _finaliseOptions (void)
415 port->mem.default_local_map = data;
416 port->mem.default_globl_map = data;
417 if (_G.asmType == ASM_TYPE_ASXXXX && IS_GB)
418 asm_addTree (&_asxxxx_gb);
424 _setDefaultOptions (void)
427 options.stackAuto = 1;
428 options.mainreturn = 1;
429 /* first the options part */
430 options.intlong_rent = 1;
431 options.float_rent = 1;
432 options.noRegParams = 1;
433 /* Default code and data locations. */
434 options.code_loc = 0x200;
438 options.data_loc = 0xC000;
442 options.data_loc = 0x8000;
445 optimize.global_cse = 1;
450 optimize.loopInvariant = 1;
451 optimize.loopInduction = 1;
457 policy is the function policy
458 params is the parameter format
463 r is 'r' for reentrant, 's' for static functions
464 s is 'c' for callee saves, 'r' for caller saves
465 p is 'p' for profiling on, 'x' for profiling off
467 rr - reentrant, caller saves
469 A combination of register short names and s to signify stack variables.
471 bds - first two args appear in BC and DE, the rest on the stack
472 s - all arguments are on the stack.
475 _mangleSupportFunctionName(char *original)
479 sprintf(buffer, "%s_rr%s_%s", original,
480 options.profile ? "f" : "x",
481 options.noRegParams ? "s" : "bds"
484 return Safe_strdup(buffer);
488 _getRegName (struct regs *reg)
499 _hasNativeMulFor (iCode *ic, sym_link *left, sym_link *right)
501 sym_link *test = NULL;
509 if ( IS_LITERAL (left))
512 val = OP_VALUE (IC_LEFT (ic));
514 else if ( IS_LITERAL (right))
517 val = OP_VALUE (IC_RIGHT (ic));
524 if ( getSize (test) <= 2)
532 /* Indicate which extended bit operations this port supports */
534 hasExtBitOp (int op, int size)
542 /* Indicate the expense of an access to an output storage class */
544 oclsExpense (struct memmap *oclass)
546 if (IN_FARSPACE(oclass))
553 #define LINKCMD "link-{port} -nf {dstfilename}"
556 "link-{port} -n -c -- {z80bases} -m -j" \
558 " {z80extralibfiles} {z80extralibpaths}" \
559 " {z80outputtypeflag} \"{linkdstfilename}\"" \
561 " \"{dstfilename}{objext}\"" \
566 "as-{port} -plosgff \"{objdstfilename}\" \"{dstfilename}{asmext}\""
573 "Zilog Z80", /* Target name */
574 NULL, /* Processor name */
578 MODEL_MEDIUM | MODEL_SMALL,
584 "-plosgff", /* Options with debug */
585 "-plosgff", /* Options without debug */
600 /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
601 1, 2, 2, 4, 2, 2, 2, 1, 4, 4
603 /* tags for generic pointers */
604 { 0x00, 0x40, 0x60, 0x80 }, /* far, near, xstack, code */
621 NULL, /* const_name */
622 "CABS", /* cabs_name */
631 /* Z80 has no native mul/div commands */
636 z80_emitDebuggerSymbol
640 3, /* sizeofElement */
641 /* The rest of these costs are bogus. They approximate */
642 /* the behavior of src/SDCCicode.c 1.207 and earlier. */
643 {4,4,4}, /* sizeofMatchJump[] */
644 {0,0,0}, /* sizeofRangeCompare[] */
645 0, /* sizeofSubtract */
646 3, /* sizeofDispatch */
658 0, /* no assembler preamble */
659 NULL, /* no genAssemblerEnd */
660 0, /* no local IVT generation code */
661 0, /* no genXINIT code */
662 NULL, /* genInitStartup */
666 _mangleSupportFunctionName,
668 hasExtBitOp, /* hasExtBitOp */
669 oclsExpense, /* oclsExpense */
671 TRUE, /* little endian */
674 1, /* transform <= to ! > */
675 1, /* transform >= to ! < */
676 1, /* transform != to !(a == b) */
678 TRUE, /* Array initializer support. */
679 0, /* no CSE cost estimation yet */
680 _z80_builtins, /* no builtin functions */
681 GPOINTER, /* treat unqualified pointers as "generic" pointers */
682 1, /* reset labelKey to 1 */
683 1, /* globals & local static allowed */
692 "Gameboy Z80-like", /* Target name */
697 MODEL_MEDIUM | MODEL_SMALL,
703 "-plosgff", /* Options with debug */
704 "-plosgff", /* Options without debug */
707 NULL /* no do_assemble function */
720 /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
721 1, 2, 2, 4, 2, 2, 2, 1, 4, 4
723 /* tags for generic pointers */
724 { 0x00, 0x40, 0x60, 0x80 }, /* far, near, xstack, code */
741 NULL, /* const_name */
742 "CABS", /* cabs_name */
751 /* gbZ80 has no native mul/div commands */
756 z80_emitDebuggerSymbol
760 3, /* sizeofElement */
761 /* The rest of these costs are bogus. They approximate */
762 /* the behavior of src/SDCCicode.c 1.207 and earlier. */
763 {4,4,4}, /* sizeofMatchJump[] */
764 {0,0,0}, /* sizeofRangeCompare[] */
765 0, /* sizeofSubtract */
766 3, /* sizeofDispatch */
778 0, /* no assembler preamble */
779 NULL, /* no genAssemblerEnd */
780 0, /* no local IVT generation code */
781 0, /* no genXINIT code */
782 NULL, /* genInitStartup */
786 _mangleSupportFunctionName,
788 hasExtBitOp, /* hasExtBitOp */
789 oclsExpense, /* oclsExpense */
791 TRUE, /* little endian */
794 1, /* transform <= to ! > */
795 1, /* transform >= to ! < */
796 1, /* transform != to !(a == b) */
798 TRUE, /* Array initializer support. */
799 0, /* no CSE cost estimation yet */
800 NULL, /* no builtin functions */
801 GPOINTER, /* treat unqualified pointers as "generic" pointers */
802 1, /* reset labelKey to 1 */
803 1, /* globals & local static allowed */