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[] = {
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;
475 if (options.nostdlib == FALSE)
481 dbuf_init(&dbuf, PATH_MAX);
483 for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
485 buildCmdLine2(path, sizeof path, "-k\"%s" DIR_SEPARATOR_STRING "{port}\" ", s);
486 dbuf_append_str(&dbuf, path);
488 buildCmdLine2(path, sizeof path, "-l\"{port}.lib\"", s);
489 dbuf_append_str(&dbuf, path);
491 setMainValue ("z80libspec", dbuf_c_str(&dbuf));
494 for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
496 struct stat stat_buf;
498 buildCmdLine2(path, sizeof path, "%s" DIR_SEPARATOR_STRING "{port}" DIR_SEPARATOR_STRING "crt0{objext}", s);
499 if (stat(path, &stat_buf) == 0)
504 setMainValue ("z80crt0", "\"crt0{objext}\"");
508 size_t len = strlen(path) + 3;
510 buf = Safe_alloc(len);
511 SNPRINTF(buf, len, "\"%s\"", path);
512 setMainValue("z80crt0", buf);
518 setMainValue ("z80libspec", "");
519 setMainValue ("z80crt0", "");
522 setMainValue ("z80extralibfiles", (s = joinStrSet(libFilesSet)));
523 Safe_free((void *)s);
524 setMainValue ("z80extralibpaths", (s = joinStrSet(libPathsSet)));
525 Safe_free((void *)s);
529 setMainValue ("z80outputtypeflag", "-Z");
530 setMainValue ("z80outext", ".gb");
534 setMainValue ("z80outputtypeflag", "-i");
535 setMainValue ("z80outext", ".ihx");
538 setMainValue ("stdobjdstfilename" , "{dstfilename}{objext}");
539 setMainValue ("stdlinkdstfilename", "{dstfilename}{z80outext}");
541 setMainValue ("z80extraobj", (s = joinStrSet(relFilesSet)));
542 Safe_free((void *)s);
544 sprintf (buffer, "-b_CODE=0x%04X -b_DATA=0x%04X", options.code_loc, options.data_loc);
545 setMainValue ("z80bases", buffer);
549 _finaliseOptions (void)
551 port->mem.default_local_map = data;
552 port->mem.default_globl_map = data;
553 if (_G.asmType == ASM_TYPE_ASXXXX && IS_GB)
554 asm_addTree (&_asxxxx_gb);
560 _setDefaultOptions (void)
563 options.stackAuto = 1;
564 options.mainreturn = 1;
565 /* first the options part */
566 options.intlong_rent = 1;
567 options.float_rent = 1;
568 options.noRegParams = 1;
569 /* Default code and data locations. */
570 options.code_loc = 0x200;
574 options.data_loc = 0xC000;
578 options.data_loc = 0x8000;
581 optimize.global_cse = 1;
586 optimize.loopInvariant = 1;
587 optimize.loopInduction = 1;
593 policy is the function policy
594 params is the parameter format
599 r is 'r' for reentrant, 's' for static functions
600 s is 'c' for callee saves, 'r' for caller saves
601 p is 'p' for profiling on, 'x' for profiling off
603 rr - reentrant, caller saves
605 A combination of register short names and s to signify stack variables.
607 bds - first two args appear in BC and DE, the rest on the stack
608 s - all arguments are on the stack.
611 _mangleSupportFunctionName(char *original)
615 sprintf(buffer, "%s_rr%s_%s", original,
616 options.profile ? "f" : "x",
617 options.noRegParams ? "s" : "bds"
620 return Safe_strdup(buffer);
624 _getRegName (struct regs *reg)
635 _hasNativeMulFor (iCode *ic, sym_link *left, sym_link *right)
637 sym_link *test = NULL;
645 if ( IS_LITERAL (left))
648 val = OP_VALUE (IC_LEFT (ic));
650 else if ( IS_LITERAL (right))
653 val = OP_VALUE (IC_RIGHT (ic));
660 if ( getSize (test) <= 2)
668 /* Indicate which extended bit operations this port supports */
670 hasExtBitOp (int op, int size)
678 /* Indicate the expense of an access to an output storage class */
680 oclsExpense (struct memmap *oclass)
682 if (IN_FARSPACE(oclass))
689 #define LINKCMD "link-{port} -nf {dstfilename}"
692 "link-{port} -n -c -- {z80bases} -m -j" \
694 " {z80extralibfiles} {z80extralibpaths}" \
695 " {z80outputtypeflag} \"{linkdstfilename}\"" \
697 " \"{dstfilename}{objext}\"" \
702 "as-{port} -plosgff \"{objdstfilename}\" \"{dstfilename}{asmext}\""
709 "Zilog Z80", /* Target name */
710 NULL, /* Processor name */
714 MODEL_MEDIUM | MODEL_SMALL,
720 "-plosgffc", /* Options with debug */
721 "-plosgff", /* Options without debug */
732 { /* Peephole optimizer */
741 /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
742 1, 2, 2, 4, 2, 2, 2, 1, 4, 4
744 /* tags for generic pointers */
745 { 0x00, 0x40, 0x60, 0x80 }, /* far, near, xstack, code */
762 NULL, /* const_name */
763 "CABS", /* cabs_name */
764 NULL, /* xabs_name */
765 NULL, /* iabs_name */
774 /* Z80 has no native mul/div commands */
779 z80_emitDebuggerSymbol
783 3, /* sizeofElement */
784 /* The rest of these costs are bogus. They approximate */
785 /* the behavior of src/SDCCicode.c 1.207 and earlier. */
786 {4,4,4}, /* sizeofMatchJump[] */
787 {0,0,0}, /* sizeofRangeCompare[] */
788 0, /* sizeofSubtract */
789 3, /* sizeofDispatch */
801 0, /* no assembler preamble */
802 NULL, /* no genAssemblerEnd */
803 0, /* no local IVT generation code */
804 0, /* no genXINIT code */
805 NULL, /* genInitStartup */
809 _mangleSupportFunctionName,
811 hasExtBitOp, /* hasExtBitOp */
812 oclsExpense, /* oclsExpense */
814 TRUE, /* little endian */
817 1, /* transform <= to ! > */
818 1, /* transform >= to ! < */
819 1, /* transform != to !(a == b) */
821 TRUE, /* Array initializer support. */
822 0, /* no CSE cost estimation yet */
823 _z80_builtins, /* no builtin functions */
824 GPOINTER, /* treat unqualified pointers as "generic" pointers */
825 1, /* reset labelKey to 1 */
826 1, /* globals & local static allowed */
835 "Gameboy Z80-like", /* Target name */
840 MODEL_MEDIUM | MODEL_SMALL,
846 "-plosgffc", /* Options with debug */
847 "-plosgff", /* Options without debug */
850 NULL /* no do_assemble function */
863 /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
864 1, 2, 2, 4, 2, 2, 2, 1, 4, 4
866 /* tags for generic pointers */
867 { 0x00, 0x40, 0x60, 0x80 }, /* far, near, xstack, code */
884 NULL, /* const_name */
885 "CABS", /* cabs_name */
886 NULL, /* xabs_name */
887 NULL, /* iabs_name */
896 /* gbZ80 has no native mul/div commands */
901 z80_emitDebuggerSymbol
905 3, /* sizeofElement */
906 /* The rest of these costs are bogus. They approximate */
907 /* the behavior of src/SDCCicode.c 1.207 and earlier. */
908 {4,4,4}, /* sizeofMatchJump[] */
909 {0,0,0}, /* sizeofRangeCompare[] */
910 0, /* sizeofSubtract */
911 3, /* sizeofDispatch */
923 0, /* no assembler preamble */
924 NULL, /* no genAssemblerEnd */
925 0, /* no local IVT generation code */
926 0, /* no genXINIT code */
927 NULL, /* genInitStartup */
931 _mangleSupportFunctionName,
933 hasExtBitOp, /* hasExtBitOp */
934 oclsExpense, /* oclsExpense */
936 TRUE, /* little endian */
939 1, /* transform <= to ! > */
940 1, /* transform >= to ! < */
941 1, /* transform != to !(a == b) */
943 TRUE, /* Array initializer support. */
944 0, /* no CSE cost estimation yet */
945 NULL, /* no builtin functions */
946 GPOINTER, /* treat unqualified pointers as "generic" pointers */
947 1, /* reset labelKey to 1 */
948 1, /* globals & local static allowed */