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 f is 'f' 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" /* MB: but the library only has hds variants ??? */
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));
655 /* 8x8 unsigned multiplication code is shorter than
656 call overhead for the multiplication routine. */
657 else if ( IS_CHAR (right) && IS_UNSIGNED (right) &&
658 IS_CHAR (left) && IS_UNSIGNED(left) && !IS_GB)
667 if ( getSize (test) <= 2)
675 /* Indicate which extended bit operations this port supports */
677 hasExtBitOp (int op, int size)
685 /* Indicate the expense of an access to an output storage class */
687 oclsExpense (struct memmap *oclass)
689 if (IN_FARSPACE(oclass))
696 #define LINKCMD "link-{port} -nf {dstfilename}"
699 "link-{port} -n -c -- {z80bases} -m -j" \
701 " {z80extralibfiles} {z80extralibpaths}" \
702 " {z80outputtypeflag} \"{linkdstfilename}\"" \
704 " \"{dstfilename}{objext}\"" \
709 "as-{port} -plosgff \"{objdstfilename}\" \"{dstfilename}{asmext}\""
716 "Zilog Z80", /* Target name */
717 NULL, /* Processor name */
721 MODEL_MEDIUM | MODEL_SMALL,
727 "-plosgffc", /* Options with debug */
728 "-plosgff", /* Options without debug */
739 { /* Peephole optimizer */
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 "-plosgffc", /* 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 */