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="
42 static char _z80_defaultRules[] =
45 #include "peeph-z80.rul"
48 static char _gbz80_defaultRules[] =
51 #include "peeph-gbz80.rul"
56 static OPTION _z80_options[] =
58 { 0, OPTION_CALLEE_SAVES_BC, &z80_opts.calleeSavesBC, "Force a called function to always save BC" },
59 { 0, OPTION_PORTMODE, NULL, "Determine PORT I/O mode (z80/z180)" },
60 { 0, OPTION_ASM, NULL, "Define assembler name (rgbds/asxxxx/isas/z80asm)" },
61 { 0, OPTION_CODE_SEG, NULL, "<name> use this name for the code segment" },
62 { 0, OPTION_CONST_SEG, NULL, "<name> use this name for the const segment" },
66 static OPTION _gbz80_options[] =
68 { 0, OPTION_BO, NULL, "<num> use code bank <num>" },
69 { 0, OPTION_BA, NULL, "<num> use data bank <num>" },
70 { 0, OPTION_CALLEE_SAVES_BC, &z80_opts.calleeSavesBC, "Force a called function to always save BC" },
71 { 0, OPTION_CODE_SEG, NULL, "<name> use this name for the code segment" },
72 { 0, OPTION_CONST_SEG, NULL, "<name> use this name for the const segment" },
89 /* determine if we can register a parameter */
94 static char *_keywords[] =
99 "at", //.p.t.20030714 adding support for 'sfr at ADDR' construct
100 "_naked", //.p.t.20030714 adding support for '_naked' functions
106 extern PORT gbz80_port;
107 extern PORT z80_port;
109 #include "mappings.i"
111 static builtins _z80_builtins[] = {
113 { "__builtin_strcpy", "v", 2, {"cg*", "cg*" } },
114 { "__builtin_memcpy", "cg*", 3, {"cg*", "cg*", "ui" } },
116 { NULL , NULL,0, {NULL}}
122 z80_opts.sub = SUB_Z80;
123 asm_addTree (&_asxxxx_z80);
129 z80_opts.sub = SUB_GBZ80;
133 _reset_regparm (void)
139 _reg_parm (sym_link * l, bool reentrant)
141 if (options.noRegParams)
147 if (_G.regParams == 2)
167 do_pragma(int id, const char *name, const char *cp)
169 struct pragma_token_s token;
173 init_pragma_token(&token);
179 struct dbuf_s buffer;
181 dbuf_init(&buffer, 128);
183 cp = get_pragma_token(cp, &token);
194 case ASM_TYPE_ASXXXX:
195 dbuf_printf (&buffer, "CODE_%d", token.val.int_val);
199 dbuf_printf (&buffer, "CODE,BANK[%d]", token.val.int_val);
203 /* PENDING: what to use for ISAS? */
204 dbuf_printf (&buffer, "CODE,BANK(%d)", token.val.int_val);
214 const char *str = get_pragma_string (&token);
216 dbuf_append_str (&buffer, (0 == strcmp("BASE", str)) ? "HOME" : str);
221 cp = get_pragma_token (cp, &token);
222 if (TOKEN_EOL != token.type)
228 dbuf_c_str (&buffer);
229 /* ugly, see comment in src/port.h (borutr) */
230 gbz80_port.mem.code_name = dbuf_detach (&buffer);
231 code->sname = gbz80_port.mem.code_name;
232 options.code_seg = (char *)gbz80_port.mem.code_name;
237 { /*.p.t.20030716 - adding pragma to manipulate z80 i/o port addressing modes */
240 cp = get_pragma_token (cp, &token);
242 if (TOKEN_EOL == token.type)
248 str = get_pragma_string (&token);
250 cp = get_pragma_token (cp, &token);
251 if (TOKEN_EOL != token.type)
257 if (!strcmp(str, "z80"))
258 { z80_opts.port_mode = 80; }
259 else if(!strcmp(str, "z180"))
260 { z80_opts.port_mode = 180; }
261 else if(!strcmp(str, "save"))
262 { z80_opts.port_back = z80_opts.port_mode; }
263 else if(!strcmp(str, "restore" ))
264 { z80_opts.port_mode = z80_opts.port_back; }
275 cp = get_pragma_token (cp, &token);
276 if (token.type == TOKEN_EOL)
282 segname = Safe_strdup (get_pragma_string(&token));
284 cp = get_pragma_token (cp, &token);
285 if (token.type != TOKEN_EOL)
294 if (options.code_seg) Safe_free(options.code_seg);
295 options.code_seg = segname;
299 if (options.const_seg) Safe_free(options.const_seg);
300 options.const_seg = segname;
310 get_pragma_token(cp, &token);
313 werror(W_BAD_PRAGMA_ARGUMENTS, name);
315 free_pragma_token(&token);
319 static struct pragma_s pragma_tbl[] = {
320 { "bank", P_BANK, 0, do_pragma },
321 { "portmode", P_PORTMODE, 0, do_pragma },
322 { "codeseg", P_CODESEG, 0, do_pragma },
323 { "constseg", P_CONSTSEG, 0, do_pragma },
324 { NULL, 0, 0, NULL },
328 _process_pragma(const char *s)
330 return process_pragma_tbl(pragma_tbl, s);
333 static const char *_gbz80_rgbasmCmd[] =
335 "rgbasm", "-o\"$1.o\"", "\"$1.asm\"", NULL
338 static const char *_gbz80_rgblinkCmd[] =
340 "xlink", "-tg", "-n\"$1.sym\"", "-m\"$1.map\"", "-zFF", "\"$1.lnk\"", NULL
344 _gbz80_rgblink (void)
348 /* first we need to create the <filename>.lnk file */
349 sprintf (scratchFileName, "%s.lnk", dstFileName);
350 if (!(lnkfile = fopen (scratchFileName, "w")))
352 werror (E_FILE_OPEN_ERR, scratchFileName);
356 fprintf (lnkfile, "[Objects]\n");
358 fprintf (lnkfile, "%s.o\n", dstFileName);
360 fputStrSet(lnkfile, relFilesSet);
362 fprintf (lnkfile, "\n[Libraries]\n");
363 /* additional libraries if any */
364 fputStrSet(lnkfile, libFilesSet);
366 fprintf (lnkfile, "\n[Output]\n" "%s.gb", dstFileName);
370 buildCmdLine (buffer,port->linker.cmd, dstFileName, NULL, NULL, NULL);
371 /* call the linker */
372 if (my_system (buffer))
374 perror ("Cannot exec linker");
380 _parseOptions (int *pargc, char **argv, int *i)
382 if (argv[*i][0] == '-')
386 if (!strncmp (argv[*i], OPTION_BO, sizeof (OPTION_BO) - 1))
389 int bank = getIntArg (OPTION_BO, argv, i, *pargc);
390 struct dbuf_s buffer;
392 dbuf_init (&buffer, 16);
393 dbuf_printf (&buffer, "CODE_%u", bank);
394 dbuf_c_str (&buffer);
395 /* ugly, see comment in src/port.h (borutr) */
396 gbz80_port.mem.code_name = dbuf_detach (&buffer);
397 options.code_seg = (char *)gbz80_port.mem.code_name;
400 else if (!strncmp (argv[*i], OPTION_BA, sizeof (OPTION_BA) - 1))
403 int bank = getIntArg (OPTION_BA, argv, i, *pargc);
404 struct dbuf_s buffer;
406 dbuf_init (&buffer, 16);
407 dbuf_printf (&buffer, "DATA_%u", bank);
408 dbuf_c_str (&buffer);
409 /* ugly, see comment in src/port.h (borutr) */
410 gbz80_port.mem.data_name = dbuf_detach (&buffer);
414 else if (!strncmp (argv[*i], OPTION_ASM, sizeof (OPTION_ASM) - 1))
416 char *asmblr = getStringArg (OPTION_ASM, argv, i, *pargc);
418 if (!strcmp (asmblr, "rgbds"))
420 asm_addTree (&_rgbds_gb);
421 gbz80_port.assembler.cmd = _gbz80_rgbasmCmd;
422 gbz80_port.linker.cmd = _gbz80_rgblinkCmd;
423 gbz80_port.linker.do_link = _gbz80_rgblink;
424 _G.asmType = ASM_TYPE_RGBDS;
427 else if (!strcmp (asmblr, "asxxxx"))
429 _G.asmType = ASM_TYPE_ASXXXX;
432 else if (!strcmp (asmblr, "isas"))
434 asm_addTree (&_isas_gb);
435 /* Munge the function prefix */
436 gbz80_port.fun_prefix = "";
437 _G.asmType = ASM_TYPE_ISAS;
440 else if (!strcmp (asmblr, "z80asm"))
442 port->assembler.externGlobal = TRUE;
443 asm_addTree (&_z80asm_z80);
444 _G.asmType = ASM_TYPE_ISAS;
448 else if (!strncmp (argv[*i], OPTION_PORTMODE, sizeof (OPTION_PORTMODE) - 1))
450 char *portmode = getStringArg (OPTION_ASM, argv, i, *pargc);
452 if (!strcmp (portmode, "z80"))
454 z80_opts.port_mode = 80;
457 else if (!strcmp (portmode, "z180"))
459 z80_opts.port_mode = 180;
463 else if (!strcmp (argv[*i], OPTION_CODE_SEG))
465 if (options.code_seg) Safe_free(options.code_seg);
466 options.code_seg = Safe_strdup(getStringArg (OPTION_CODE_SEG, argv, i, *pargc));
469 else if (!strcmp (argv[*i], OPTION_CONST_SEG))
471 if (options.const_seg) Safe_free(options.const_seg);
472 options.const_seg = Safe_strdup(getStringArg (OPTION_CONST_SEG, argv, i, *pargc));
484 if (options.nostdlib == FALSE)
490 dbuf_init(&dbuf, PATH_MAX);
492 for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
494 buildCmdLine2(path, sizeof path, "-k\"%s" DIR_SEPARATOR_STRING "{port}\" ", s);
495 dbuf_append_str(&dbuf, path);
497 buildCmdLine2(path, sizeof path, "-l\"{port}.lib\"", s);
498 dbuf_append_str(&dbuf, path);
500 setMainValue ("z80libspec", dbuf_c_str(&dbuf));
503 for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
505 struct stat stat_buf;
507 buildCmdLine2(path, sizeof path, "%s" DIR_SEPARATOR_STRING "{port}" DIR_SEPARATOR_STRING "crt0{objext}", s);
508 if (stat(path, &stat_buf) == 0)
513 setMainValue ("z80crt0", "\"crt0{objext}\"");
517 size_t len = strlen(path) + 3;
519 buf = Safe_alloc(len);
520 SNPRINTF(buf, len, "\"%s\"", path);
521 setMainValue("z80crt0", buf);
527 setMainValue ("z80libspec", "");
528 setMainValue ("z80crt0", "");
531 setMainValue ("z80extralibfiles", (s = joinStrSet(libFilesSet)));
532 Safe_free((void *)s);
533 setMainValue ("z80extralibpaths", (s = joinStrSet(libPathsSet)));
534 Safe_free((void *)s);
538 setMainValue ("z80outputtypeflag", "-z");
539 setMainValue ("z80outext", ".gb");
543 setMainValue ("z80outputtypeflag", "-i");
544 setMainValue ("z80outext", ".ihx");
547 setMainValue ("stdobjdstfilename" , "{dstfilename}{objext}");
548 setMainValue ("stdlinkdstfilename", "{dstfilename}{z80outext}");
550 setMainValue ("z80extraobj", (s = joinStrSet(relFilesSet)));
551 Safe_free((void *)s);
553 sprintf (buffer, "-b_CODE=0x%04X -b_DATA=0x%04X", options.code_loc, options.data_loc);
554 setMainValue ("z80bases", buffer);
558 _finaliseOptions (void)
560 port->mem.default_local_map = data;
561 port->mem.default_globl_map = data;
562 if (_G.asmType == ASM_TYPE_ASXXXX && IS_GB)
563 asm_addTree (&_asxxxx_gb);
569 _setDefaultOptions (void)
572 options.stackAuto = 1;
573 options.mainreturn = 1;
574 /* first the options part */
575 options.intlong_rent = 1;
576 options.float_rent = 1;
577 options.noRegParams = 1;
578 /* Default code and data locations. */
579 options.code_loc = 0x200;
583 options.data_loc = 0xC000;
587 options.data_loc = 0x8000;
590 optimize.global_cse = 1;
595 optimize.loopInvariant = 1;
596 optimize.loopInduction = 1;
602 policy is the function policy
603 params is the parameter format
608 r is 'r' for reentrant, 's' for static functions
609 s is 'c' for callee saves, 'r' for caller saves
610 p is 'p' for profiling on, 'x' for profiling off
612 rr - reentrant, caller saves
614 A combination of register short names and s to signify stack variables.
616 bds - first two args appear in BC and DE, the rest on the stack
617 s - all arguments are on the stack.
620 _mangleSupportFunctionName(char *original)
624 sprintf(buffer, "%s_rr%s_%s", original,
625 options.profile ? "f" : "x",
626 options.noRegParams ? "s" : "bds"
629 return Safe_strdup(buffer);
633 _getRegName (struct regs *reg)
644 _hasNativeMulFor (iCode *ic, sym_link *left, sym_link *right)
646 sym_link *test = NULL;
654 if ( IS_LITERAL (left))
657 val = OP_VALUE (IC_LEFT (ic));
659 else if ( IS_LITERAL (right))
662 val = OP_VALUE (IC_RIGHT (ic));
669 if ( getSize (test) <= 2)
677 /* Indicate which extended bit operations this port supports */
679 hasExtBitOp (int op, int size)
687 /* Indicate the expense of an access to an output storage class */
689 oclsExpense (struct memmap *oclass)
691 if (IN_FARSPACE(oclass))
698 #define LINKCMD "link-{port} -nf {dstfilename}"
701 "link-{port} -n -c -- {z80bases} -m -j" \
703 " {z80extralibfiles} {z80extralibpaths}" \
704 " {z80outputtypeflag} \"{linkdstfilename}\"" \
706 " \"{dstfilename}{objext}\"" \
711 "as-{port} -plosgff \"{objdstfilename}\" \"{dstfilename}{asmext}\""
718 "Zilog Z80", /* Target name */
719 NULL, /* Processor name */
723 MODEL_MEDIUM | MODEL_SMALL,
729 "-plosgff", /* Options with debug */
730 "-plosgff", /* Options without debug */
745 /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
746 1, 2, 2, 4, 2, 2, 2, 1, 4, 4
748 /* tags for generic pointers */
749 { 0x00, 0x40, 0x60, 0x80 }, /* far, near, xstack, code */
766 NULL, /* const_name */
767 "CABS", /* cabs_name */
768 NULL, /* xabs_name */
769 NULL, /* iabs_name */
778 /* Z80 has no native mul/div commands */
783 z80_emitDebuggerSymbol
787 3, /* sizeofElement */
788 /* The rest of these costs are bogus. They approximate */
789 /* the behavior of src/SDCCicode.c 1.207 and earlier. */
790 {4,4,4}, /* sizeofMatchJump[] */
791 {0,0,0}, /* sizeofRangeCompare[] */
792 0, /* sizeofSubtract */
793 3, /* sizeofDispatch */
805 0, /* no assembler preamble */
806 NULL, /* no genAssemblerEnd */
807 0, /* no local IVT generation code */
808 0, /* no genXINIT code */
809 NULL, /* genInitStartup */
813 _mangleSupportFunctionName,
815 hasExtBitOp, /* hasExtBitOp */
816 oclsExpense, /* oclsExpense */
818 TRUE, /* little endian */
821 1, /* transform <= to ! > */
822 1, /* transform >= to ! < */
823 1, /* transform != to !(a == b) */
825 TRUE, /* Array initializer support. */
826 0, /* no CSE cost estimation yet */
827 _z80_builtins, /* no builtin functions */
828 GPOINTER, /* treat unqualified pointers as "generic" pointers */
829 1, /* reset labelKey to 1 */
830 1, /* globals & local static allowed */
839 "Gameboy Z80-like", /* Target name */
844 MODEL_MEDIUM | MODEL_SMALL,
850 "-plosgff", /* Options with debug */
851 "-plosgff", /* Options without debug */
854 NULL /* no do_assemble function */
867 /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
868 1, 2, 2, 4, 2, 2, 2, 1, 4, 4
870 /* tags for generic pointers */
871 { 0x00, 0x40, 0x60, 0x80 }, /* far, near, xstack, code */
888 NULL, /* const_name */
889 "CABS", /* cabs_name */
890 NULL, /* xabs_name */
891 NULL, /* iabs_name */
900 /* gbZ80 has no native mul/div commands */
905 z80_emitDebuggerSymbol
909 3, /* sizeofElement */
910 /* The rest of these costs are bogus. They approximate */
911 /* the behavior of src/SDCCicode.c 1.207 and earlier. */
912 {4,4,4}, /* sizeofMatchJump[] */
913 {0,0,0}, /* sizeofRangeCompare[] */
914 0, /* sizeofSubtract */
915 3, /* sizeofDispatch */
927 0, /* no assembler preamble */
928 NULL, /* no genAssemblerEnd */
929 0, /* no local IVT generation code */
930 0, /* no genXINIT code */
931 NULL, /* genInitStartup */
935 _mangleSupportFunctionName,
937 hasExtBitOp, /* hasExtBitOp */
938 oclsExpense, /* oclsExpense */
940 TRUE, /* little endian */
943 1, /* transform <= to ! > */
944 1, /* transform >= to ! < */
945 1, /* transform != to !(a == b) */
947 TRUE, /* Array initializer support. */
948 0, /* no CSE cost estimation yet */
949 NULL, /* no builtin functions */
950 GPOINTER, /* treat unqualified pointers as "generic" pointers */
951 1, /* reset labelKey to 1 */
952 1, /* globals & local static allowed */