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 -------------------------------------------------------------------------*/
31 #include "dbuf_string.h"
33 #define OPTION_BO "-bo"
34 #define OPTION_BA "-ba"
35 #define OPTION_CODE_SEG "--codeseg"
36 #define OPTION_CONST_SEG "--constseg"
37 #define OPTION_CALLEE_SAVES_BC "--callee-saves-bc"
38 #define OPTION_PORTMODE "--portmode="
39 #define OPTION_ASM "--asm="
40 #define OPTION_NO_STD_CRT0 "--no-std-crt0"
43 static char _z80_defaultRules[] =
46 #include "peeph-z80.rul"
49 static char _gbz80_defaultRules[] =
52 #include "peeph-gbz80.rul"
57 static OPTION _z80_options[] =
59 { 0, OPTION_CALLEE_SAVES_BC, &z80_opts.calleeSavesBC, "Force a called function to always save BC" },
60 { 0, OPTION_PORTMODE, NULL, "Determine PORT I/O mode (z80/z180)" },
61 { 0, OPTION_ASM, NULL, "Define assembler name (rgbds/asxxxx/isas/z80asm)" },
62 { 0, OPTION_CODE_SEG, NULL, "<name> use this name for the code segment" },
63 { 0, OPTION_CONST_SEG, NULL, "<name> use this name for the const segment" },
64 { 0, OPTION_NO_STD_CRT0, &options.no_std_crt0, "For the z80/gbz80 do not link default crt0.o"},
68 static OPTION _gbz80_options[] =
70 { 0, OPTION_BO, NULL, "<num> use code bank <num>" },
71 { 0, OPTION_BA, NULL, "<num> use data bank <num>" },
72 { 0, OPTION_CALLEE_SAVES_BC, &z80_opts.calleeSavesBC, "Force a called function to always save BC" },
73 { 0, OPTION_CODE_SEG, NULL, "<name> use this name for the code segment" },
74 { 0, OPTION_CONST_SEG, NULL, "<name> use this name for the const segment" },
75 { 0, OPTION_NO_STD_CRT0, &options.no_std_crt0, "For the z80/gbz80 do not link default crt0.o"},
92 /* determine if we can register a parameter */
97 static char *_keywords[] =
102 "at", //.p.t.20030714 adding support for 'sfr at ADDR' construct
103 "_naked", //.p.t.20030714 adding support for '_naked' functions
109 extern PORT gbz80_port;
110 extern PORT z80_port;
112 #include "mappings.i"
114 static builtins _z80_builtins[] = {
116 { "__builtin_strcpy", "v", 2, {"cg*", "cg*" } },
117 { "__builtin_memcpy", "cg*", 3, {"cg*", "cg*", "ui" } },
119 { NULL , NULL,0, {NULL}}
125 z80_opts.sub = SUB_Z80;
126 asm_addTree (&_asxxxx_z80);
132 z80_opts.sub = SUB_GBZ80;
136 _reset_regparm (void)
142 _reg_parm (sym_link * l, bool reentrant)
144 if (options.noRegParams)
150 if (_G.regParams == 2)
170 do_pragma(int id, const char *name, const char *cp)
172 struct pragma_token_s token;
176 init_pragma_token(&token);
182 struct dbuf_s buffer;
184 dbuf_init(&buffer, 128);
186 cp = get_pragma_token(cp, &token);
197 case ASM_TYPE_ASXXXX:
198 dbuf_printf (&buffer, "CODE_%d", token.val.int_val);
202 dbuf_printf (&buffer, "CODE,BANK[%d]", token.val.int_val);
206 /* PENDING: what to use for ISAS? */
207 dbuf_printf (&buffer, "CODE,BANK(%d)", token.val.int_val);
217 const char *str = get_pragma_string (&token);
219 dbuf_append_str (&buffer, (0 == strcmp("BASE", str)) ? "HOME" : str);
224 cp = get_pragma_token (cp, &token);
225 if (TOKEN_EOL != token.type)
231 dbuf_c_str (&buffer);
232 /* ugly, see comment in src/port.h (borutr) */
233 gbz80_port.mem.code_name = dbuf_detach (&buffer);
234 code->sname = gbz80_port.mem.code_name;
235 options.code_seg = (char *)gbz80_port.mem.code_name;
240 { /*.p.t.20030716 - adding pragma to manipulate z80 i/o port addressing modes */
243 cp = get_pragma_token (cp, &token);
245 if (TOKEN_EOL == token.type)
251 str = get_pragma_string (&token);
253 cp = get_pragma_token (cp, &token);
254 if (TOKEN_EOL != token.type)
260 if (!strcmp(str, "z80"))
261 { z80_opts.port_mode = 80; }
262 else if(!strcmp(str, "z180"))
263 { z80_opts.port_mode = 180; }
264 else if(!strcmp(str, "save"))
265 { z80_opts.port_back = z80_opts.port_mode; }
266 else if(!strcmp(str, "restore" ))
267 { z80_opts.port_mode = z80_opts.port_back; }
278 cp = get_pragma_token (cp, &token);
279 if (token.type == TOKEN_EOL)
285 segname = Safe_strdup (get_pragma_string(&token));
287 cp = get_pragma_token (cp, &token);
288 if (token.type != TOKEN_EOL)
297 if (options.code_seg) Safe_free(options.code_seg);
298 options.code_seg = segname;
302 if (options.const_seg) Safe_free(options.const_seg);
303 options.const_seg = segname;
313 get_pragma_token(cp, &token);
316 werror(W_BAD_PRAGMA_ARGUMENTS, name);
318 free_pragma_token(&token);
322 static struct pragma_s pragma_tbl[] = {
323 { "bank", P_BANK, 0, do_pragma },
324 { "portmode", P_PORTMODE, 0, do_pragma },
325 { "codeseg", P_CODESEG, 0, do_pragma },
326 { "constseg", P_CONSTSEG, 0, do_pragma },
327 { NULL, 0, 0, NULL },
331 _process_pragma(const char *s)
333 return process_pragma_tbl(pragma_tbl, s);
336 static const char *_gbz80_rgbasmCmd[] =
338 "rgbasm", "-o\"$1.o\"", "\"$1.asm\"", NULL
341 static const char *_gbz80_rgblinkCmd[] =
343 "xlink", "-tg", "-n\"$1.sym\"", "-m\"$1.map\"", "-zFF", "\"$1.lnk\"", NULL
347 _gbz80_rgblink (void)
351 /* first we need to create the <filename>.lnk file */
352 sprintf (scratchFileName, "%s.lnk", dstFileName);
353 if (!(lnkfile = fopen (scratchFileName, "w")))
355 werror (E_FILE_OPEN_ERR, scratchFileName);
359 fprintf (lnkfile, "[Objects]\n");
361 fprintf (lnkfile, "%s.o\n", dstFileName);
363 fputStrSet(lnkfile, relFilesSet);
365 fprintf (lnkfile, "\n[Libraries]\n");
366 /* additional libraries if any */
367 fputStrSet(lnkfile, libFilesSet);
369 fprintf (lnkfile, "\n[Output]\n" "%s.gb", dstFileName);
373 buildCmdLine (buffer,port->linker.cmd, dstFileName, NULL, NULL, NULL);
374 /* call the linker */
375 if (my_system (buffer))
377 perror ("Cannot exec linker");
383 _parseOptions (int *pargc, char **argv, int *i)
385 if (argv[*i][0] == '-')
389 if (!strncmp (argv[*i], OPTION_BO, sizeof (OPTION_BO) - 1))
392 int bank = getIntArg (OPTION_BO, argv, i, *pargc);
393 struct dbuf_s buffer;
395 dbuf_init (&buffer, 16);
396 dbuf_printf (&buffer, "CODE_%u", bank);
397 dbuf_c_str (&buffer);
398 /* ugly, see comment in src/port.h (borutr) */
399 gbz80_port.mem.code_name = dbuf_detach (&buffer);
400 options.code_seg = (char *)gbz80_port.mem.code_name;
403 else if (!strncmp (argv[*i], OPTION_BA, sizeof (OPTION_BA) - 1))
406 int bank = getIntArg (OPTION_BA, argv, i, *pargc);
407 struct dbuf_s buffer;
409 dbuf_init (&buffer, 16);
410 dbuf_printf (&buffer, "DATA_%u", bank);
411 dbuf_c_str (&buffer);
412 /* ugly, see comment in src/port.h (borutr) */
413 gbz80_port.mem.data_name = dbuf_detach (&buffer);
417 else if (!strncmp (argv[*i], OPTION_ASM, sizeof (OPTION_ASM) - 1))
419 char *asmblr = getStringArg (OPTION_ASM, argv, i, *pargc);
421 if (!strcmp (asmblr, "rgbds"))
423 asm_addTree (&_rgbds_gb);
424 gbz80_port.assembler.cmd = _gbz80_rgbasmCmd;
425 gbz80_port.linker.cmd = _gbz80_rgblinkCmd;
426 gbz80_port.linker.do_link = _gbz80_rgblink;
427 _G.asmType = ASM_TYPE_RGBDS;
430 else if (!strcmp (asmblr, "asxxxx"))
432 _G.asmType = ASM_TYPE_ASXXXX;
435 else if (!strcmp (asmblr, "isas"))
437 asm_addTree (&_isas_gb);
438 /* Munge the function prefix */
439 gbz80_port.fun_prefix = "";
440 _G.asmType = ASM_TYPE_ISAS;
443 else if (!strcmp (asmblr, "z80asm"))
445 port->assembler.externGlobal = TRUE;
446 asm_addTree (&_z80asm_z80);
447 _G.asmType = ASM_TYPE_ISAS;
451 else if (!strncmp (argv[*i], OPTION_PORTMODE, sizeof (OPTION_PORTMODE) - 1))
453 char *portmode = getStringArg (OPTION_ASM, argv, i, *pargc);
455 if (!strcmp (portmode, "z80"))
457 z80_opts.port_mode = 80;
460 else if (!strcmp (portmode, "z180"))
462 z80_opts.port_mode = 180;
466 else if (!strcmp (argv[*i], OPTION_CODE_SEG))
468 if (options.code_seg) Safe_free(options.code_seg);
469 options.code_seg = Safe_strdup(getStringArg (OPTION_CODE_SEG, argv, i, *pargc));
472 else if (!strcmp (argv[*i], OPTION_CONST_SEG))
474 if (options.const_seg) Safe_free(options.const_seg);
475 options.const_seg = Safe_strdup(getStringArg (OPTION_CONST_SEG, argv, i, *pargc));
487 if (options.nostdlib == FALSE)
493 dbuf_init(&dbuf, PATH_MAX);
495 for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
497 buildCmdLine2(path, sizeof path, "-k\"%s" DIR_SEPARATOR_STRING "{port}\" ", s);
498 dbuf_append_str(&dbuf, path);
500 buildCmdLine2(path, sizeof path, "-l\"{port}.lib\"", s);
501 dbuf_append_str(&dbuf, path);
503 setMainValue ("z80libspec", dbuf_c_str(&dbuf));
506 for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
508 struct stat stat_buf;
510 buildCmdLine2(path, sizeof path, "%s" DIR_SEPARATOR_STRING "{port}" DIR_SEPARATOR_STRING "crt0{objext}", s);
511 if (stat(path, &stat_buf) == 0)
516 setMainValue ("z80crt0", "\"crt0{objext}\"");
520 size_t len = strlen(path) + 3;
522 buf = Safe_alloc(len);
523 SNPRINTF(buf, len, "\"%s\"", path);
524 setMainValue("z80crt0", buf);
530 setMainValue ("z80libspec", "");
531 setMainValue ("z80crt0", "");
534 setMainValue ("z80extralibfiles", (s = joinStrSet(libFilesSet)));
535 Safe_free((void *)s);
536 setMainValue ("z80extralibpaths", (s = joinStrSet(libPathsSet)));
537 Safe_free((void *)s);
541 setMainValue ("z80outputtypeflag", "-z");
542 setMainValue ("z80outext", ".gb");
546 setMainValue ("z80outputtypeflag", "-i");
547 setMainValue ("z80outext", ".ihx");
550 setMainValue ("stdobjdstfilename" , "{dstfilename}{objext}");
551 setMainValue ("stdlinkdstfilename", "{dstfilename}{z80outext}");
553 setMainValue ("z80extraobj", (s = joinStrSet(relFilesSet)));
554 Safe_free((void *)s);
556 sprintf (buffer, "-b_CODE=0x%04X -b_DATA=0x%04X", options.code_loc, options.data_loc);
557 setMainValue ("z80bases", buffer);
561 _finaliseOptions (void)
563 port->mem.default_local_map = data;
564 port->mem.default_globl_map = data;
565 if (_G.asmType == ASM_TYPE_ASXXXX && IS_GB)
566 asm_addTree (&_asxxxx_gb);
572 _setDefaultOptions (void)
575 options.stackAuto = 1;
576 options.mainreturn = 1;
577 /* first the options part */
578 options.intlong_rent = 1;
579 options.float_rent = 1;
580 options.noRegParams = 1;
581 /* Default code and data locations. */
582 options.code_loc = 0x200;
586 options.data_loc = 0xC000;
590 options.data_loc = 0x8000;
593 optimize.global_cse = 1;
598 optimize.loopInvariant = 1;
599 optimize.loopInduction = 1;
605 policy is the function policy
606 params is the parameter format
611 r is 'r' for reentrant, 's' for static functions
612 s is 'c' for callee saves, 'r' for caller saves
613 p is 'p' for profiling on, 'x' for profiling off
615 rr - reentrant, caller saves
617 A combination of register short names and s to signify stack variables.
619 bds - first two args appear in BC and DE, the rest on the stack
620 s - all arguments are on the stack.
623 _mangleSupportFunctionName(char *original)
627 sprintf(buffer, "%s_rr%s_%s", original,
628 options.profile ? "f" : "x",
629 options.noRegParams ? "s" : "bds"
632 return Safe_strdup(buffer);
636 _getRegName (struct regs *reg)
647 _hasNativeMulFor (iCode *ic, sym_link *left, sym_link *right)
649 sym_link *test = NULL;
657 if ( IS_LITERAL (left))
660 val = OP_VALUE (IC_LEFT (ic));
662 else if ( IS_LITERAL (right))
665 val = OP_VALUE (IC_RIGHT (ic));
672 if ( getSize (test) <= 2)
680 /* Indicate which extended bit operations this port supports */
682 hasExtBitOp (int op, int size)
690 /* Indicate the expense of an access to an output storage class */
692 oclsExpense (struct memmap *oclass)
694 if (IN_FARSPACE(oclass))
701 #define LINKCMD "link-{port} -nf {dstfilename}"
704 "link-{port} -n -c -- {z80bases} -m -j" \
706 " {z80extralibfiles} {z80extralibpaths}" \
707 " {z80outputtypeflag} \"{linkdstfilename}\"" \
709 " \"{dstfilename}{objext}\"" \
714 "as-{port} -plosgff \"{objdstfilename}\" \"{dstfilename}{asmext}\""
721 "Zilog Z80", /* Target name */
722 NULL, /* Processor name */
726 MODEL_MEDIUM | MODEL_SMALL,
732 "-plosgff", /* Options with debug */
733 "-plosgff", /* Options without debug */
748 /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
749 1, 2, 2, 4, 2, 2, 2, 1, 4, 4
751 /* tags for generic pointers */
752 { 0x00, 0x40, 0x60, 0x80 }, /* far, near, xstack, code */
769 NULL, /* const_name */
770 "CABS", /* cabs_name */
771 NULL, /* xabs_name */
772 NULL, /* iabs_name */
781 /* Z80 has no native mul/div commands */
786 z80_emitDebuggerSymbol
790 3, /* sizeofElement */
791 /* The rest of these costs are bogus. They approximate */
792 /* the behavior of src/SDCCicode.c 1.207 and earlier. */
793 {4,4,4}, /* sizeofMatchJump[] */
794 {0,0,0}, /* sizeofRangeCompare[] */
795 0, /* sizeofSubtract */
796 3, /* sizeofDispatch */
808 0, /* no assembler preamble */
809 NULL, /* no genAssemblerEnd */
810 0, /* no local IVT generation code */
811 0, /* no genXINIT code */
812 NULL, /* genInitStartup */
816 _mangleSupportFunctionName,
818 hasExtBitOp, /* hasExtBitOp */
819 oclsExpense, /* oclsExpense */
821 TRUE, /* little endian */
824 1, /* transform <= to ! > */
825 1, /* transform >= to ! < */
826 1, /* transform != to !(a == b) */
828 TRUE, /* Array initializer support. */
829 0, /* no CSE cost estimation yet */
830 _z80_builtins, /* no builtin functions */
831 GPOINTER, /* treat unqualified pointers as "generic" pointers */
832 1, /* reset labelKey to 1 */
833 1, /* globals & local static allowed */
842 "Gameboy Z80-like", /* Target name */
847 MODEL_MEDIUM | MODEL_SMALL,
853 "-plosgff", /* Options with debug */
854 "-plosgff", /* Options without debug */
857 NULL /* no do_assemble function */
870 /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
871 1, 2, 2, 4, 2, 2, 2, 1, 4, 4
873 /* tags for generic pointers */
874 { 0x00, 0x40, 0x60, 0x80 }, /* far, near, xstack, code */
891 NULL, /* const_name */
892 "CABS", /* cabs_name */
893 NULL, /* xabs_name */
894 NULL, /* iabs_name */
903 /* gbZ80 has no native mul/div commands */
908 z80_emitDebuggerSymbol
912 3, /* sizeofElement */
913 /* The rest of these costs are bogus. They approximate */
914 /* the behavior of src/SDCCicode.c 1.207 and earlier. */
915 {4,4,4}, /* sizeofMatchJump[] */
916 {0,0,0}, /* sizeofRangeCompare[] */
917 0, /* sizeofSubtract */
918 3, /* sizeofDispatch */
930 0, /* no assembler preamble */
931 NULL, /* no genAssemblerEnd */
932 0, /* no local IVT generation code */
933 0, /* no genXINIT code */
934 NULL, /* genInitStartup */
938 _mangleSupportFunctionName,
940 hasExtBitOp, /* hasExtBitOp */
941 oclsExpense, /* oclsExpense */
943 TRUE, /* little endian */
946 1, /* transform <= to ! > */
947 1, /* transform >= to ! < */
948 1, /* transform != to !(a == b) */
950 TRUE, /* Array initializer support. */
951 0, /* no CSE cost estimation yet */
952 NULL, /* no builtin functions */
953 GPOINTER, /* treat unqualified pointers as "generic" pointers */
954 1, /* reset labelKey to 1 */
955 1, /* globals & local static allowed */