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", "vg*", 3, {"vg*", "vg*", "ui" } },
118 { NULL , NULL,0, {NULL}}
124 z80_opts.sub = SUB_Z80;
125 asm_addTree (&_asxxxx_z80);
131 z80_opts.sub = SUB_GBZ80;
135 _reset_regparm (void)
141 _reg_parm (sym_link * l, bool reentrant)
143 if (options.noRegParams)
149 if (_G.regParams == 2)
169 do_pragma(int id, const char *name, const char *cp)
171 struct pragma_token_s token;
175 init_pragma_token(&token);
181 struct dbuf_s buffer;
183 dbuf_init(&buffer, 128);
185 cp = get_pragma_token(cp, &token);
196 case ASM_TYPE_ASXXXX:
197 dbuf_printf (&buffer, "CODE_%d", token.val.int_val);
201 dbuf_printf (&buffer, "CODE,BANK[%d]", token.val.int_val);
205 /* PENDING: what to use for ISAS? */
206 dbuf_printf (&buffer, "CODE,BANK(%d)", token.val.int_val);
216 const char *str = get_pragma_string (&token);
218 dbuf_append_str (&buffer, (0 == strcmp("BASE", str)) ? "HOME" : str);
223 cp = get_pragma_token (cp, &token);
224 if (TOKEN_EOL != token.type)
230 dbuf_c_str (&buffer);
231 /* ugly, see comment in src/port.h (borutr) */
232 gbz80_port.mem.code_name = dbuf_detach (&buffer);
233 code->sname = gbz80_port.mem.code_name;
234 options.code_seg = (char *)gbz80_port.mem.code_name;
239 { /*.p.t.20030716 - adding pragma to manipulate z80 i/o port addressing modes */
242 cp = get_pragma_token (cp, &token);
244 if (TOKEN_EOL == token.type)
250 str = get_pragma_string (&token);
252 cp = get_pragma_token (cp, &token);
253 if (TOKEN_EOL != token.type)
259 if (!strcmp(str, "z80"))
260 { z80_opts.port_mode = 80; }
261 else if(!strcmp(str, "z180"))
262 { z80_opts.port_mode = 180; }
263 else if(!strcmp(str, "save"))
264 { z80_opts.port_back = z80_opts.port_mode; }
265 else if(!strcmp(str, "restore" ))
266 { z80_opts.port_mode = z80_opts.port_back; }
277 cp = get_pragma_token (cp, &token);
278 if (token.type == TOKEN_EOL)
284 segname = Safe_strdup (get_pragma_string(&token));
286 cp = get_pragma_token (cp, &token);
287 if (token.type != TOKEN_EOL)
296 if (options.code_seg) Safe_free(options.code_seg);
297 options.code_seg = segname;
301 if (options.const_seg) Safe_free(options.const_seg);
302 options.const_seg = segname;
312 get_pragma_token(cp, &token);
315 werror(W_BAD_PRAGMA_ARGUMENTS, name);
317 free_pragma_token(&token);
321 static struct pragma_s pragma_tbl[] = {
322 { "bank", P_BANK, 0, do_pragma },
323 { "portmode", P_PORTMODE, 0, do_pragma },
324 { "codeseg", P_CODESEG, 0, do_pragma },
325 { "constseg", P_CONSTSEG, 0, do_pragma },
326 { NULL, 0, 0, NULL },
330 _process_pragma(const char *s)
332 return process_pragma_tbl(pragma_tbl, s);
335 static const char *_gbz80_rgbasmCmd[] =
337 "rgbasm", "-o\"$1.o\"", "\"$1.asm\"", NULL
340 static const char *_gbz80_rgblinkCmd[] =
342 "xlink", "-tg", "-n\"$1.sym\"", "-m\"$1.map\"", "-zFF", "\"$1.lnk\"", NULL
346 _gbz80_rgblink (void)
350 /* first we need to create the <filename>.lnk file */
351 sprintf (scratchFileName, "%s.lnk", dstFileName);
352 if (!(lnkfile = fopen (scratchFileName, "w")))
354 werror (E_FILE_OPEN_ERR, scratchFileName);
358 fprintf (lnkfile, "[Objects]\n");
360 fprintf (lnkfile, "%s.o\n", dstFileName);
362 fputStrSet(lnkfile, relFilesSet);
364 fprintf (lnkfile, "\n[Libraries]\n");
365 /* additional libraries if any */
366 fputStrSet(lnkfile, libFilesSet);
368 fprintf (lnkfile, "\n[Output]\n" "%s.gb", dstFileName);
372 buildCmdLine (buffer,port->linker.cmd, dstFileName, NULL, NULL, NULL);
373 /* call the linker */
374 if (my_system (buffer))
376 perror ("Cannot exec linker");
382 _parseOptions (int *pargc, char **argv, int *i)
384 if (argv[*i][0] == '-')
388 if (!strncmp (argv[*i], OPTION_BO, sizeof (OPTION_BO) - 1))
391 int bank = getIntArg (OPTION_BO, argv, i, *pargc);
392 struct dbuf_s buffer;
394 dbuf_init (&buffer, 16);
395 dbuf_printf (&buffer, "CODE_%u", bank);
396 dbuf_c_str (&buffer);
397 /* ugly, see comment in src/port.h (borutr) */
398 gbz80_port.mem.code_name = dbuf_detach (&buffer);
399 options.code_seg = (char *)gbz80_port.mem.code_name;
402 else if (!strncmp (argv[*i], OPTION_BA, sizeof (OPTION_BA) - 1))
405 int bank = getIntArg (OPTION_BA, argv, i, *pargc);
406 struct dbuf_s buffer;
408 dbuf_init (&buffer, 16);
409 dbuf_printf (&buffer, "DATA_%u", bank);
410 dbuf_c_str (&buffer);
411 /* ugly, see comment in src/port.h (borutr) */
412 gbz80_port.mem.data_name = dbuf_detach (&buffer);
416 else if (!strncmp (argv[*i], OPTION_ASM, sizeof (OPTION_ASM) - 1))
418 char *asmblr = getStringArg (OPTION_ASM, argv, i, *pargc);
420 if (!strcmp (asmblr, "rgbds"))
422 asm_addTree (&_rgbds_gb);
423 gbz80_port.assembler.cmd = _gbz80_rgbasmCmd;
424 gbz80_port.linker.cmd = _gbz80_rgblinkCmd;
425 gbz80_port.linker.do_link = _gbz80_rgblink;
426 _G.asmType = ASM_TYPE_RGBDS;
429 else if (!strcmp (asmblr, "asxxxx"))
431 _G.asmType = ASM_TYPE_ASXXXX;
434 else if (!strcmp (asmblr, "isas"))
436 asm_addTree (&_isas_gb);
437 /* Munge the function prefix */
438 gbz80_port.fun_prefix = "";
439 _G.asmType = ASM_TYPE_ISAS;
442 else if (!strcmp (asmblr, "z80asm"))
444 port->assembler.externGlobal = TRUE;
445 asm_addTree (&_z80asm_z80);
446 _G.asmType = ASM_TYPE_ISAS;
450 else if (!strncmp (argv[*i], OPTION_PORTMODE, sizeof (OPTION_PORTMODE) - 1))
452 char *portmode = getStringArg (OPTION_ASM, argv, i, *pargc);
454 if (!strcmp (portmode, "z80"))
456 z80_opts.port_mode = 80;
459 else if (!strcmp (portmode, "z180"))
461 z80_opts.port_mode = 180;
474 if (options.nostdlib == FALSE)
480 dbuf_init(&dbuf, PATH_MAX);
482 for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
484 buildCmdLine2(path, sizeof path, "-k\"%s" DIR_SEPARATOR_STRING "{port}\" ", s);
485 dbuf_append_str(&dbuf, path);
487 buildCmdLine2(path, sizeof path, "-l\"{port}.lib\"", s);
488 dbuf_append_str(&dbuf, path);
490 setMainValue ("z80libspec", dbuf_c_str(&dbuf));
493 for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
495 struct stat stat_buf;
497 buildCmdLine2(path, sizeof path, "%s" DIR_SEPARATOR_STRING "{port}" DIR_SEPARATOR_STRING "crt0{objext}", s);
498 if (stat(path, &stat_buf) == 0)
503 setMainValue ("z80crt0", "\"crt0{objext}\"");
507 size_t len = strlen(path) + 3;
509 buf = Safe_alloc(len);
510 SNPRINTF(buf, len, "\"%s\"", path);
511 setMainValue("z80crt0", buf);
517 setMainValue ("z80libspec", "");
518 setMainValue ("z80crt0", "");
521 setMainValue ("z80extralibfiles", (s = joinStrSet(libFilesSet)));
522 Safe_free((void *)s);
523 setMainValue ("z80extralibpaths", (s = joinStrSet(libPathsSet)));
524 Safe_free((void *)s);
528 setMainValue ("z80outputtypeflag", "-Z");
529 setMainValue ("z80outext", ".gb");
533 setMainValue ("z80outputtypeflag", "-i");
534 setMainValue ("z80outext", ".ihx");
537 setMainValue ("stdobjdstfilename" , "{dstfilename}{objext}");
538 setMainValue ("stdlinkdstfilename", "{dstfilename}{z80outext}");
540 setMainValue ("z80extraobj", (s = joinStrSet(relFilesSet)));
541 Safe_free((void *)s);
543 sprintf (buffer, "-b_CODE=0x%04X -b_DATA=0x%04X", options.code_loc, options.data_loc);
544 setMainValue ("z80bases", buffer);
548 _finaliseOptions (void)
550 port->mem.default_local_map = data;
551 port->mem.default_globl_map = data;
552 if (_G.asmType == ASM_TYPE_ASXXXX && IS_GB)
553 asm_addTree (&_asxxxx_gb);
559 _setDefaultOptions (void)
562 options.stackAuto = 1;
563 options.mainreturn = 1;
564 /* first the options part */
565 options.intlong_rent = 1;
566 options.float_rent = 1;
567 options.noRegParams = 1;
568 /* Default code and data locations. */
569 options.code_loc = 0x200;
573 options.data_loc = 0xC000;
577 options.data_loc = 0x8000;
580 optimize.global_cse = 1;
585 optimize.loopInvariant = 1;
586 optimize.loopInduction = 1;
592 policy is the function policy
593 params is the parameter format
598 r is 'r' for reentrant, 's' for static functions
599 s is 'c' for callee saves, 'r' for caller saves
600 f is 'f' for profiling on, 'x' for profiling off
602 rr - reentrant, caller saves
604 A combination of register short names and s to signify stack variables.
606 bds - first two args appear in BC and DE, the rest on the stack
607 s - all arguments are on the stack.
610 _mangleSupportFunctionName(char *original)
614 sprintf(buffer, "%s_rr%s_%s", original,
615 options.profile ? "f" : "x",
616 options.noRegParams ? "s" : "bds" /* MB: but the library only has hds variants ??? */
619 return Safe_strdup(buffer);
623 _getRegName (struct regs *reg)
634 _hasNativeMulFor (iCode *ic, sym_link *left, sym_link *right)
636 sym_link *test = NULL;
644 if ( IS_LITERAL (left))
647 val = OP_VALUE (IC_LEFT (ic));
649 else if ( IS_LITERAL (right))
652 val = OP_VALUE (IC_RIGHT (ic));
654 /* 8x8 unsigned multiplication code is shorter than
655 call overhead for the multiplication routine. */
656 else if ( IS_CHAR (right) && IS_UNSIGNED (right) &&
657 IS_CHAR (left) && IS_UNSIGNED(left) && !IS_GB)
666 if ( getSize (test) <= 2)
674 /* Indicate which extended bit operations this port supports */
676 hasExtBitOp (int op, int size)
684 /* Indicate the expense of an access to an output storage class */
686 oclsExpense (struct memmap *oclass)
688 if (IN_FARSPACE(oclass))
695 #define LINKCMD "link-{port} -nf {dstfilename}"
698 "link-{port} -n -c -- {z80bases} -m -j" \
700 " {z80extralibfiles} {z80extralibpaths}" \
701 " {z80outputtypeflag} \"{linkdstfilename}\"" \
703 " \"{dstfilename}{objext}\"" \
708 "as-{port} -plosgff \"{objdstfilename}\" \"{dstfilename}{asmext}\""
715 "Zilog Z80", /* Target name */
716 NULL, /* Processor name */
720 MODEL_MEDIUM | MODEL_SMALL,
726 "-plosgffc", /* Options with debug */
727 "-plosgff", /* Options without debug */
738 { /* Peephole optimizer */
747 /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
748 1, 2, 2, 4, 2, 2, 2, 1, 4, 4
750 /* tags for generic pointers */
751 { 0x00, 0x40, 0x60, 0x80 }, /* far, near, xstack, code */
768 NULL, /* const_name */
769 "CABS", /* cabs_name */
770 NULL, /* xabs_name */
771 NULL, /* iabs_name */
780 /* Z80 has no native mul/div commands */
785 z80_emitDebuggerSymbol
789 3, /* sizeofElement */
790 /* The rest of these costs are bogus. They approximate */
791 /* the behavior of src/SDCCicode.c 1.207 and earlier. */
792 {4,4,4}, /* sizeofMatchJump[] */
793 {0,0,0}, /* sizeofRangeCompare[] */
794 0, /* sizeofSubtract */
795 3, /* sizeofDispatch */
807 0, /* no assembler preamble */
808 NULL, /* no genAssemblerEnd */
809 0, /* no local IVT generation code */
810 0, /* no genXINIT code */
811 NULL, /* genInitStartup */
815 _mangleSupportFunctionName,
817 hasExtBitOp, /* hasExtBitOp */
818 oclsExpense, /* oclsExpense */
820 TRUE, /* little endian */
823 1, /* transform <= to ! > */
824 1, /* transform >= to ! < */
825 1, /* transform != to !(a == b) */
827 TRUE, /* Array initializer support. */
828 0, /* no CSE cost estimation yet */
829 _z80_builtins, /* builtin functions */
830 GPOINTER, /* treat unqualified pointers as "generic" pointers */
831 1, /* reset labelKey to 1 */
832 1, /* globals & local static allowed */
841 "Gameboy Z80-like", /* Target name */
846 MODEL_MEDIUM | MODEL_SMALL,
852 "-plosgffc", /* Options with debug */
853 "-plosgff", /* Options without debug */
856 NULL /* no do_assemble function */
869 /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
870 1, 2, 2, 4, 2, 2, 2, 1, 4, 4
872 /* tags for generic pointers */
873 { 0x00, 0x40, 0x60, 0x80 }, /* far, near, xstack, code */
890 NULL, /* const_name */
891 "CABS", /* cabs_name */
892 NULL, /* xabs_name */
893 NULL, /* iabs_name */
902 /* gbZ80 has no native mul/div commands */
907 z80_emitDebuggerSymbol
911 3, /* sizeofElement */
912 /* The rest of these costs are bogus. They approximate */
913 /* the behavior of src/SDCCicode.c 1.207 and earlier. */
914 {4,4,4}, /* sizeofMatchJump[] */
915 {0,0,0}, /* sizeofRangeCompare[] */
916 0, /* sizeofSubtract */
917 3, /* sizeofDispatch */
929 0, /* no assembler preamble */
930 NULL, /* no genAssemblerEnd */
931 0, /* no local IVT generation code */
932 0, /* no genXINIT code */
933 NULL, /* genInitStartup */
937 _mangleSupportFunctionName,
939 hasExtBitOp, /* hasExtBitOp */
940 oclsExpense, /* oclsExpense */
942 TRUE, /* little endian */
945 1, /* transform <= to ! > */
946 1, /* transform >= to ! < */
947 1, /* transform != to !(a == b) */
949 TRUE, /* Array initializer support. */
950 0, /* no CSE cost estimation yet */
951 NULL, /* no builtin functions */
952 GPOINTER, /* treat unqualified pointers as "generic" pointers */
953 1, /* reset labelKey to 1 */
954 1, /* globals & local static allowed */