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 -------------------------------------------------------------------------*/
30 #include "dbuf_string.h"
32 static char _z80_defaultRules[] =
35 #include "peeph-z80.rul"
38 static char _gbz80_defaultRules[] =
41 #include "peeph-gbz80.rul"
46 static OPTION _z80_options[] =
48 { 0, "--callee-saves-bc", &z80_opts.calleeSavesBC, "Force a called function to always save BC" },
49 { 0, "--portmode=", NULL, "Determine PORT I/O mode (z80/z180)" },
53 static OPTION _gbz80_options[] =
55 { 0, "--callee-saves-bc", &z80_opts.calleeSavesBC, "Force a called function to always save BC" },
72 /* determine if we can register a parameter */
77 static char *_keywords[] =
82 "at", //.p.t.20030714 adding support for 'sfr at ADDR' construct
83 "_naked", //.p.t.20030714 adding support for '_naked' functions
89 extern PORT gbz80_port;
94 static builtins _z80_builtins[] = {
96 { "__builtin_strcpy", "v", 2, {"cg*", "cg*" } },
97 { "__builtin_memcpy", "cg*", 3, {"cg*", "cg*", "ui" } },
99 { NULL , NULL,0, {NULL}}
105 z80_opts.sub = SUB_Z80;
106 asm_addTree (&_asxxxx_z80);
112 z80_opts.sub = SUB_GBZ80;
116 _reset_regparm (void)
122 _reg_parm (sym_link * l, bool reentrant)
124 if (options.noRegParams)
130 if (_G.regParams == 2)
148 do_pragma(int id, const char *name, const char *cp)
150 struct pragma_token_s token;
154 init_pragma_token(&token);
162 cp = get_pragma_token(cp, &token);
173 case ASM_TYPE_ASXXXX:
174 sprintf(buffer, "CODE_%d", token.val.int_val);
178 sprintf(buffer, "CODE,BANK[%d]", token.val.int_val);
182 /* PENDING: what to use for ISAS? */
183 sprintf (buffer, "CODE,BANK(%d)", token.val.int_val);
193 const char *str = get_pragma_string(&token);
195 strncpyz(buffer, (0 == strcmp("BASE", str)) ? "HOME" : str, sizeof buffer);
200 cp = get_pragma_token(cp, &token);
201 if (TOKEN_EOL != token.type)
207 gbz80_port.mem.code_name = Safe_strdup (buffer);
208 code->sname = gbz80_port.mem.code_name;
209 options.code_seg = gbz80_port.mem.code_name;
214 { /*.p.t.20030716 - adding pragma to manipulate z80 i/o port addressing modes */
217 cp = get_pragma_token(cp, &token);
219 if (TOKEN_EOL == token.type)
225 str = get_pragma_string(&token);
227 cp = get_pragma_token(cp, &token);
228 if (TOKEN_EOL != token.type)
234 if (!strcmp(str, "z80"))
235 { z80_opts.port_mode = 80; }
236 else if(!strcmp(str, "z180"))
237 { z80_opts.port_mode = 180; }
238 else if(!strcmp(str, "save"))
239 { z80_opts.port_back = z80_opts.port_mode; }
240 else if(!strcmp(str, "restore" ))
241 { z80_opts.port_mode = z80_opts.port_back; }
252 get_pragma_token(cp, &token);
255 werror(W_BAD_PRAGMA_ARGUMENTS, name);
257 free_pragma_token(&token);
261 static struct pragma_s pragma_tbl[] = {
262 { "bank", P_BANK, 0, do_pragma },
263 { "portmode", P_PORTMODE, 0, do_pragma },
264 { NULL, 0, 0, NULL },
268 _process_pragma(const char *s)
270 return process_pragma_tbl(pragma_tbl, s);
273 static const char *_gbz80_rgbasmCmd[] =
275 "rgbasm", "-o\"$1.o\"", "\"$1.asm\"", NULL
278 static const char *_gbz80_rgblinkCmd[] =
280 "xlink", "-tg", "-n\"$1.sym\"", "-m\"$1.map\"", "-zFF", "\"$1.lnk\"", NULL
284 _gbz80_rgblink (void)
288 /* first we need to create the <filename>.lnk file */
289 sprintf (scratchFileName, "%s.lnk", dstFileName);
290 if (!(lnkfile = fopen (scratchFileName, "w")))
292 werror (E_FILE_OPEN_ERR, scratchFileName);
296 fprintf (lnkfile, "[Objects]\n");
298 fprintf (lnkfile, "%s.o\n", dstFileName);
300 fputStrSet(lnkfile, relFilesSet);
302 fprintf (lnkfile, "\n[Libraries]\n");
303 /* additional libraries if any */
304 fputStrSet(lnkfile, libFilesSet);
306 fprintf (lnkfile, "\n[Output]\n" "%s.gb", dstFileName);
310 buildCmdLine (buffer,port->linker.cmd, dstFileName, NULL, NULL, NULL);
311 /* call the linker */
312 if (my_system (buffer))
314 perror ("Cannot exec linker");
320 _parseOptions (int *pargc, char **argv, int *i)
322 if (argv[*i][0] == '-')
324 if (argv[*i][1] == 'b' && IS_GB)
326 int bank = atoi (argv[*i] + 3);
332 sprintf (buffer, "CODE_%u", bank);
333 gbz80_port.mem.code_name = Safe_strdup (buffer);
334 options.code_seg = gbz80_port.mem.code_name;
338 sprintf (buffer, "DATA_%u", bank);
339 gbz80_port.mem.data_name = Safe_strdup (buffer);
343 else if (!strncmp (argv[*i], "--asm=", 6))
345 if (!strcmp (argv[*i], "--asm=rgbds"))
347 asm_addTree (&_rgbds_gb);
348 gbz80_port.assembler.cmd = _gbz80_rgbasmCmd;
349 gbz80_port.linker.cmd = _gbz80_rgblinkCmd;
350 gbz80_port.linker.do_link = _gbz80_rgblink;
351 _G.asmType = ASM_TYPE_RGBDS;
354 else if (!strcmp (argv[*i], "--asm=asxxxx"))
356 _G.asmType = ASM_TYPE_ASXXXX;
359 else if (!strcmp (argv[*i], "--asm=isas"))
361 asm_addTree (&_isas_gb);
362 /* Munge the function prefix */
363 gbz80_port.fun_prefix = "";
364 _G.asmType = ASM_TYPE_ISAS;
367 else if (!strcmp (argv[*i], "--asm=z80asm"))
369 port->assembler.externGlobal = TRUE;
370 asm_addTree (&_z80asm_z80);
371 _G.asmType = ASM_TYPE_ISAS;
375 else if (!strncmp (argv[*i], "--portmode=", 11))
377 if (!strcmp (argv[*i], "--portmode=z80"))
379 z80_opts.port_mode = 80;
382 else if (!strcmp (argv[*i], "--portmode=z180"))
384 z80_opts.port_mode = 180;
397 if (options.nostdlib == FALSE)
403 dbuf_init(&dbuf, PATH_MAX);
405 for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
407 buildCmdLine2(path, sizeof path, "-k\"%s" DIR_SEPARATOR_STRING "{port}\" ", s);
408 dbuf_append_str(&dbuf, path);
410 buildCmdLine2(path, sizeof path, "-l\"{port}.lib\"", s);
411 dbuf_append_str(&dbuf, path);
413 setMainValue ("z80libspec", dbuf_c_str(&dbuf));
416 for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
418 struct stat stat_buf;
420 buildCmdLine2(path, sizeof path, "%s" DIR_SEPARATOR_STRING "{port}" DIR_SEPARATOR_STRING "crt0{objext}", s);
421 if (stat(path, &stat_buf) == 0)
426 setMainValue ("z80crt0", "\"crt0{objext}\"");
430 size_t len = strlen(path) + 3;
432 buf = Safe_alloc(len);
433 SNPRINTF(buf, len, "\"%s\"", path);
434 setMainValue("z80crt0", buf);
440 setMainValue ("z80libspec", "");
441 setMainValue ("z80crt0", "");
444 setMainValue ("z80extralibfiles", (s = joinStrSet(libFilesSet)));
445 Safe_free((void *)s);
446 setMainValue ("z80extralibpaths", (s = joinStrSet(libPathsSet)));
447 Safe_free((void *)s);
451 setMainValue ("z80outputtypeflag", "-z");
452 setMainValue ("z80outext", ".gb");
456 setMainValue ("z80outputtypeflag", "-i");
457 setMainValue ("z80outext", ".ihx");
460 setMainValue ("stdobjdstfilename" , "{dstfilename}{objext}");
461 setMainValue ("stdlinkdstfilename", "{dstfilename}{z80outext}");
463 setMainValue ("z80extraobj", (s = joinStrSet(relFilesSet)));
464 Safe_free((void *)s);
466 sprintf (buffer, "-b_CODE=0x%04X -b_DATA=0x%04X", options.code_loc, options.data_loc);
467 setMainValue ("z80bases", buffer);
471 _finaliseOptions (void)
473 port->mem.default_local_map = data;
474 port->mem.default_globl_map = data;
475 if (_G.asmType == ASM_TYPE_ASXXXX && IS_GB)
476 asm_addTree (&_asxxxx_gb);
482 _setDefaultOptions (void)
485 options.stackAuto = 1;
486 options.mainreturn = 1;
487 /* first the options part */
488 options.intlong_rent = 1;
489 options.float_rent = 1;
490 options.noRegParams = 1;
491 /* Default code and data locations. */
492 options.code_loc = 0x200;
496 options.data_loc = 0xC000;
500 options.data_loc = 0x8000;
503 optimize.global_cse = 1;
508 optimize.loopInvariant = 1;
509 optimize.loopInduction = 1;
515 policy is the function policy
516 params is the parameter format
521 r is 'r' for reentrant, 's' for static functions
522 s is 'c' for callee saves, 'r' for caller saves
523 p is 'p' for profiling on, 'x' for profiling off
525 rr - reentrant, caller saves
527 A combination of register short names and s to signify stack variables.
529 bds - first two args appear in BC and DE, the rest on the stack
530 s - all arguments are on the stack.
533 _mangleSupportFunctionName(char *original)
537 sprintf(buffer, "%s_rr%s_%s", original,
538 options.profile ? "f" : "x",
539 options.noRegParams ? "s" : "bds"
542 return Safe_strdup(buffer);
546 _getRegName (struct regs *reg)
557 _hasNativeMulFor (iCode *ic, sym_link *left, sym_link *right)
559 sym_link *test = NULL;
567 if ( IS_LITERAL (left))
570 val = OP_VALUE (IC_LEFT (ic));
572 else if ( IS_LITERAL (right))
575 val = OP_VALUE (IC_RIGHT (ic));
582 if ( getSize (test) <= 2)
590 /* Indicate which extended bit operations this port supports */
592 hasExtBitOp (int op, int size)
600 /* Indicate the expense of an access to an output storage class */
602 oclsExpense (struct memmap *oclass)
604 if (IN_FARSPACE(oclass))
611 #define LINKCMD "link-{port} -nf {dstfilename}"
614 "link-{port} -n -c -- {z80bases} -m -j" \
616 " {z80extralibfiles} {z80extralibpaths}" \
617 " {z80outputtypeflag} \"{linkdstfilename}\"" \
619 " \"{dstfilename}{objext}\"" \
624 "as-{port} -plosgff \"{objdstfilename}\" \"{dstfilename}{asmext}\""
631 "Zilog Z80", /* Target name */
632 NULL, /* Processor name */
636 MODEL_MEDIUM | MODEL_SMALL,
642 "-plosgff", /* Options with debug */
643 "-plosgff", /* Options without debug */
658 /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
659 1, 2, 2, 4, 2, 2, 2, 1, 4, 4
661 /* tags for generic pointers */
662 { 0x00, 0x40, 0x60, 0x80 }, /* far, near, xstack, code */
679 NULL, /* const_name */
680 "CABS", /* cabs_name */
681 NULL, /* xabs_name */
682 NULL, /* iabs_name */
691 /* Z80 has no native mul/div commands */
696 z80_emitDebuggerSymbol
700 3, /* sizeofElement */
701 /* The rest of these costs are bogus. They approximate */
702 /* the behavior of src/SDCCicode.c 1.207 and earlier. */
703 {4,4,4}, /* sizeofMatchJump[] */
704 {0,0,0}, /* sizeofRangeCompare[] */
705 0, /* sizeofSubtract */
706 3, /* sizeofDispatch */
718 0, /* no assembler preamble */
719 NULL, /* no genAssemblerEnd */
720 0, /* no local IVT generation code */
721 0, /* no genXINIT code */
722 NULL, /* genInitStartup */
726 _mangleSupportFunctionName,
728 hasExtBitOp, /* hasExtBitOp */
729 oclsExpense, /* oclsExpense */
731 TRUE, /* little endian */
734 1, /* transform <= to ! > */
735 1, /* transform >= to ! < */
736 1, /* transform != to !(a == b) */
738 TRUE, /* Array initializer support. */
739 0, /* no CSE cost estimation yet */
740 _z80_builtins, /* no builtin functions */
741 GPOINTER, /* treat unqualified pointers as "generic" pointers */
742 1, /* reset labelKey to 1 */
743 1, /* globals & local static allowed */
752 "Gameboy Z80-like", /* Target name */
757 MODEL_MEDIUM | MODEL_SMALL,
763 "-plosgff", /* Options with debug */
764 "-plosgff", /* Options without debug */
767 NULL /* no do_assemble function */
780 /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
781 1, 2, 2, 4, 2, 2, 2, 1, 4, 4
783 /* tags for generic pointers */
784 { 0x00, 0x40, 0x60, 0x80 }, /* far, near, xstack, code */
801 NULL, /* const_name */
802 "CABS", /* cabs_name */
803 NULL, /* xabs_name */
804 NULL, /* iabs_name */
813 /* gbZ80 has no native mul/div commands */
818 z80_emitDebuggerSymbol
822 3, /* sizeofElement */
823 /* The rest of these costs are bogus. They approximate */
824 /* the behavior of src/SDCCicode.c 1.207 and earlier. */
825 {4,4,4}, /* sizeofMatchJump[] */
826 {0,0,0}, /* sizeofRangeCompare[] */
827 0, /* sizeofSubtract */
828 3, /* sizeofDispatch */
840 0, /* no assembler preamble */
841 NULL, /* no genAssemblerEnd */
842 0, /* no local IVT generation code */
843 0, /* no genXINIT code */
844 NULL, /* genInitStartup */
848 _mangleSupportFunctionName,
850 hasExtBitOp, /* hasExtBitOp */
851 oclsExpense, /* oclsExpense */
853 TRUE, /* little endian */
856 1, /* transform <= to ! > */
857 1, /* transform >= to ! < */
858 1, /* transform != to !(a == b) */
860 TRUE, /* Array initializer support. */
861 0, /* no CSE cost estimation yet */
862 NULL, /* no builtin functions */
863 GPOINTER, /* treat unqualified pointers as "generic" pointers */
864 1, /* reset labelKey to 1 */
865 1, /* globals & local static allowed */