/* tc-z80.c -- Assemble code for the Zilog Z80 and ASCII R800 Copyright 2005, 2006 Free Software Foundation, Inc. Contributed by Arnold Metselaar This file is part of GAS, the GNU Assembler. GAS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GAS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GAS; see the file COPYING. If not, write to the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ #include "as.h" #include "safe-ctype.h" #include "subsegs.h" /* Exported constants. */ const char comment_chars[] = ";\0"; const char line_comment_chars[] = "#;\0"; const char line_separator_chars[] = "\0"; const char EXP_CHARS[] = "eE\0"; const char FLT_CHARS[] = "RrFf\0"; /* For machine specific options. */ const char * md_shortopts = ""; /* None yet. */ enum options { OPTION_MACH_Z80 = OPTION_MD_BASE, OPTION_MACH_R800, OPTION_MACH_IUD, OPTION_MACH_WUD, OPTION_MACH_FUD, OPTION_MACH_IUP, OPTION_MACH_WUP, OPTION_MACH_FUP }; #define INS_Z80 1 #define INS_UNDOC 2 #define INS_UNPORT 4 #define INS_R800 8 struct option md_longopts[] = { { "z80", no_argument, NULL, OPTION_MACH_Z80}, { "r800", no_argument, NULL, OPTION_MACH_R800}, { "ignore-undocumented-instructions", no_argument, NULL, OPTION_MACH_IUD }, { "Wnud", no_argument, NULL, OPTION_MACH_IUD }, { "warn-undocumented-instructions", no_argument, NULL, OPTION_MACH_WUD }, { "Wud", no_argument, NULL, OPTION_MACH_WUD }, { "forbid-undocumented-instructions", no_argument, NULL, OPTION_MACH_FUD }, { "Fud", no_argument, NULL, OPTION_MACH_FUD }, { "ignore-unportable-instructions", no_argument, NULL, OPTION_MACH_IUP }, { "Wnup", no_argument, NULL, OPTION_MACH_IUP }, { "warn-unportable-instructions", no_argument, NULL, OPTION_MACH_WUP }, { "Wup", no_argument, NULL, OPTION_MACH_WUP }, { "forbid-unportable-instructions", no_argument, NULL, OPTION_MACH_FUP }, { "Fup", no_argument, NULL, OPTION_MACH_FUP }, { NULL, no_argument, NULL, 0 } } ; size_t md_longopts_size = sizeof (md_longopts); extern int coff_flags; /* Instruction classes that silently assembled. */ static int ins_ok = INS_Z80 | INS_UNDOC; /* Instruction classes that generate errors. */ static int ins_err = INS_R800; /* Instruction classes actually used, determines machine type. */ static int ins_used = INS_Z80; int md_parse_option (int c, char* arg ATTRIBUTE_UNUSED) { switch (c) { default: return 0; case OPTION_MACH_Z80: ins_ok &= ~INS_R800; ins_err |= INS_R800; break; case OPTION_MACH_R800: ins_ok = INS_Z80 | INS_UNDOC | INS_R800; ins_err = INS_UNPORT; break; case OPTION_MACH_IUD: ins_ok |= INS_UNDOC; ins_err &= ~INS_UNDOC; break; case OPTION_MACH_IUP: ins_ok |= INS_UNDOC | INS_UNPORT; ins_err &= ~(INS_UNDOC | INS_UNPORT); break; case OPTION_MACH_WUD: if ((ins_ok & INS_R800) == 0) { ins_ok &= ~(INS_UNDOC|INS_UNPORT); ins_err &= ~INS_UNDOC; } break; case OPTION_MACH_WUP: ins_ok &= ~INS_UNPORT; ins_err &= ~(INS_UNDOC|INS_UNPORT); break; case OPTION_MACH_FUD: if ((ins_ok & INS_R800) == 0) { ins_ok &= (INS_UNDOC | INS_UNPORT); ins_err |= INS_UNDOC | INS_UNPORT; } break; case OPTION_MACH_FUP: ins_ok &= ~INS_UNPORT; ins_err |= INS_UNPORT; break; } return 1; } void md_show_usage (FILE * f) { fprintf (f, "\n\ CPU model/instruction set options:\n\ \n\ -z80\t\t assemble for Z80\n\ -ignore-undocumented-instructions\n\ -Wnud\n\ \tsilently assemble undocumented Z80-instructions that work on R800\n\ -ignore-unportable-instructions\n\ -Wnup\n\ \tsilently assemble all undocumented Z80-instructions\n\ -warn-undocumented-instructions\n\ -Wud\n\ \tissue warnings for undocumented Z80-instructions that work on R800\n\ -warn-unportable-instructions\n\ -Wup\n\ \tissue warnings for other undocumented Z80-instructions\n\ -forbid-undocumented-instructions\n\ -Fud\n\ \ttreat all undocumented z80-instructions as errors\n\ -forbid-unportable-instructions\n\ -Fup\n\ \ttreat undocumented z80-instructions that do not work on R800 as errors\n\ -r800\t assemble for R800\n\n\ Default: -z80 -ignore-undocument-instructions -warn-unportable-instructions.\n"); } static symbolS * zero; void md_begin (void) { expressionS nul; char * p; p = input_line_pointer; input_line_pointer = "0"; nul.X_md=0; expression (& nul); input_line_pointer = p; zero = make_expr_symbol (& nul); /* We do not use relaxation (yet). */ linkrelax = 0; } void z80_md_end (void) { int mach_type; if (ins_used & (INS_UNPORT | INS_R800)) ins_used |= INS_UNDOC; switch (ins_used) { case INS_Z80: mach_type = bfd_mach_z80strict; break; case INS_Z80|INS_UNDOC: mach_type = bfd_mach_z80; break; case INS_Z80|INS_UNDOC|INS_UNPORT: mach_type = bfd_mach_z80full; break; case INS_Z80|INS_UNDOC|INS_R800: mach_type = bfd_mach_r800; break; default: mach_type = 0; } bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach_type); } static const char * skip_space (const char *s) { while (*s == ' ' || *s == '\t') ++s; return s; } /* A non-zero return-value causes a continue in the function read_a_source_file () in ../read.c. */ int z80_start_line_hook (void) { char *p, quote; char buf[4]; /* Convert one character constants. */ for (p = input_line_pointer; *p && *p != '\n'; ++p) { switch (*p) { case '\'': if (p[1] != 0 && p[1] != '\'' && p[2] == '\'') { snprintf (buf, 4, "%3d", (unsigned char)p[1]); *p++ = buf[0]; *p++ = buf[1]; *p++ = buf[2]; break; } case '"': for (quote = *p++; quote != *p && '\n' != *p; ++p) /* No escapes. */ ; if (quote != *p) { as_bad (_("-- unterminated string")); ignore_rest_of_line (); return 1; } break; } } /* Check for