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, &options.code_seg, "<name> use this name for the code segment", CLAT_STRING },
63 { 0, OPTION_CONST_SEG, &options.const_seg, "<name> use this name for the const segment", CLAT_STRING },
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, &options.code_seg, "<name> use this name for the code segment", CLAT_STRING },
74 { 0, OPTION_CONST_SEG, &options.const_seg, "<name> use this name for the const segment", CLAT_STRING },
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[] = {
115 { "__builtin_memcpy", "vg*", 3, {"vg*", "vg*", "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;
472 if (options.nostdlib == FALSE)
478 dbuf_init(&dbuf, PATH_MAX);
480 for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
482 buildCmdLine2(path, sizeof path, "-k\"%s" DIR_SEPARATOR_STRING "{port}\" ", s);
483 dbuf_append_str(&dbuf, path);
485 buildCmdLine2(path, sizeof path, "-l\"{port}.lib\"", s);
486 dbuf_append_str(&dbuf, path);
488 setMainValue ("z80libspec", dbuf_c_str(&dbuf));
491 for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
493 struct stat stat_buf;
495 buildCmdLine2(path, sizeof path, "%s" DIR_SEPARATOR_STRING "{port}" DIR_SEPARATOR_STRING "crt0{objext}", s);
496 if (stat(path, &stat_buf) == 0)
501 setMainValue ("z80crt0", "\"crt0{objext}\"");
505 size_t len = strlen(path) + 3;
507 buf = Safe_alloc(len);
508 SNPRINTF(buf, len, "\"%s\"", path);
509 setMainValue("z80crt0", buf);
515 setMainValue ("z80libspec", "");
516 setMainValue ("z80crt0", "");
519 setMainValue ("z80extralibfiles", (s = joinStrSet(libFilesSet)));
520 Safe_free((void *)s);
521 setMainValue ("z80extralibpaths", (s = joinStrSet(libPathsSet)));
522 Safe_free((void *)s);
526 setMainValue ("z80outputtypeflag", "-Z");
527 setMainValue ("z80outext", ".gb");
531 setMainValue ("z80outputtypeflag", "-i");
532 setMainValue ("z80outext", ".ihx");
535 setMainValue ("stdobjdstfilename" , "{dstfilename}{objext}");
536 setMainValue ("stdlinkdstfilename", "{dstfilename}{z80outext}");
538 setMainValue ("z80extraobj", (s = joinStrSet(relFilesSet)));
539 Safe_free((void *)s);
541 sprintf (buffer, "-b_CODE=0x%04X -b_DATA=0x%04X", options.code_loc, options.data_loc);
542 setMainValue ("z80bases", buffer);
546 _finaliseOptions (void)
548 port->mem.default_local_map = data;
549 port->mem.default_globl_map = data;
550 if (_G.asmType == ASM_TYPE_ASXXXX && IS_GB)
551 asm_addTree (&_asxxxx_gb);
557 _setDefaultOptions (void)
560 options.stackAuto = 1;
561 options.mainreturn = 1;
562 /* first the options part */
563 options.intlong_rent = 1;
564 options.float_rent = 1;
565 options.noRegParams = 1;
566 /* Default code and data locations. */
567 options.code_loc = 0x200;
571 options.data_loc = 0xC000;
575 options.data_loc = 0x8000;
578 optimize.global_cse = 1;
583 optimize.loopInvariant = 1;
584 optimize.loopInduction = 1;
590 policy is the function policy
591 params is the parameter format
596 r is 'r' for reentrant, 's' for static functions
597 s is 'c' for callee saves, 'r' for caller saves
598 f is 'f' for profiling on, 'x' for profiling off
600 rr - reentrant, caller saves
602 A combination of register short names and s to signify stack variables.
604 bds - first two args appear in BC and DE, the rest on the stack
605 s - all arguments are on the stack.
608 _mangleSupportFunctionName(char *original)
612 sprintf(buffer, "%s_rr%s_%s", original,
613 options.profile ? "f" : "x",
614 options.noRegParams ? "s" : "bds" /* MB: but the library only has hds variants ??? */
617 return Safe_strdup(buffer);
621 _getRegName (struct regs *reg)
632 _hasNativeMulFor (iCode *ic, sym_link *left, sym_link *right)
634 sym_link *test = NULL;
642 if ( IS_LITERAL (left))
645 val = OP_VALUE (IC_LEFT (ic));
647 else if ( IS_LITERAL (right))
650 val = OP_VALUE (IC_RIGHT (ic));
652 /* 8x8 unsigned multiplication code is shorter than
653 call overhead for the multiplication routine. */
654 else if ( IS_CHAR (right) && IS_UNSIGNED (right) &&
655 IS_CHAR (left) && IS_UNSIGNED(left) && !IS_GB)
664 if ( getSize (test) <= 2)
672 /* Indicate which extended bit operations this port supports */
674 hasExtBitOp (int op, int size)
682 /* Indicate the expense of an access to an output storage class */
684 oclsExpense (struct memmap *oclass)
686 if (IN_FARSPACE(oclass))
693 #define LINKCMD "link-{port} -nf {dstfilename}"
696 "link-{port} -n -c -- {z80bases} -m -j" \
698 " {z80extralibfiles} {z80extralibpaths}" \
699 " {z80outputtypeflag} \"{linkdstfilename}\"" \
701 " \"{dstfilename}{objext}\"" \
706 "as-{port} -plosgff \"{objdstfilename}\" \"{dstfilename}{asmext}\""
713 "Zilog Z80", /* Target name */
714 NULL, /* Processor name */
718 MODEL_MEDIUM | MODEL_SMALL,
724 "-plosgffc", /* Options with debug */
725 "-plosgff", /* Options without debug */
736 { /* Peephole optimizer */
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, /* 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 "-plosgffc", /* 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 */