📄 tc-z8k.c
字号:
/* tc-z8k.c -- Assemble code for the Zilog Z800n Copyright 1992, 1993, 1994, 1995, 1996, 1998, 2000 Free Software Foundation, Inc. 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* Written By Steve Chamberlain <sac@cygnus.com>. */#define DEFINE_TABLE#include <stdio.h>#include "opcodes/z8k-opc.h"#include "as.h"#include "bfd.h"#include <ctype.h>const char comment_chars[] = "!";const char line_comment_chars[] = "#";const char line_separator_chars[] = ";";extern int machine;extern int coff_flags;int segmented_mode;const int md_reloc_size;void cons ();voids_segm (){ segmented_mode = 1; machine = bfd_mach_z8001; coff_flags = F_Z8001;}voids_unseg (){ segmented_mode = 0; machine = bfd_mach_z8002; coff_flags = F_Z8002;}static voideven (){ frag_align (1, 0, 0); record_alignment (now_seg, 1);}void obj_coff_section ();inttohex (c) int c;{ if (isdigit (c)) return c - '0'; if (islower (c)) return c - 'a' + 10; return c - 'A' + 10;}voidsval (){ SKIP_WHITESPACE (); if (*input_line_pointer == '\'') { int c; input_line_pointer++; c = *input_line_pointer++; while (c != '\'') { if (c == '%') { c = (tohex (input_line_pointer[0]) << 4) | tohex (input_line_pointer[1]); input_line_pointer += 2; } FRAG_APPEND_1_CHAR (c); c = *input_line_pointer++; } demand_empty_rest_of_line (); }}/* This table describes all the machine specific pseudo-ops the assembler has to support. The fields are: pseudo-op name without dot function to call to execute this pseudo-op Integer arg to pass to the function */const pseudo_typeS md_pseudo_table[] = { {"int" , cons , 2}, {"data.b" , cons , 1}, {"data.w" , cons , 2}, {"data.l" , cons , 4}, {"form" , listing_psize , 0}, {"heading", listing_title , 0}, {"import" , s_ignore , 0}, {"page" , listing_eject , 0}, {"program", s_ignore , 0}, {"z8001" , s_segm , 0}, {"z8002" , s_unseg , 0}, {"segm" , s_segm , 0}, {"unsegm" , s_unseg , 0}, {"unseg" , s_unseg , 0}, {"name" , s_app_file , 0}, {"global" , s_globl , 0}, {"wval" , cons , 2}, {"lval" , cons , 4}, {"bval" , cons , 1}, {"sval" , sval , 0}, {"rsect" , obj_coff_section, 0}, {"sect" , obj_coff_section, 0}, {"block" , s_space , 0}, {"even" , even , 0}, {0 , 0 , 0}};const char EXP_CHARS[] = "eE";/* Chars that mean this number is a floating point constant. As in 0f12.456 or 0d1.2345e12 */const char FLT_CHARS[] = "rRsSfFdDxXpP";/* Opcode mnemonics. */static struct hash_control *opcode_hash_control;voidmd_begin (){ opcode_entry_type *opcode; char *prev_name = ""; int idx = 0; opcode_hash_control = hash_new (); for (opcode = z8k_table; opcode->name; opcode++) { /* Only enter unique codes into the table. */ if (strcmp (opcode->name, prev_name)) { hash_insert (opcode_hash_control, opcode->name, (char *) opcode); idx++; } opcode->idx = idx; prev_name = opcode->name; } /* Default to z8002. */ s_unseg (); /* Insert the pseudo ops, too. */ for (idx = 0; md_pseudo_table[idx].poc_name; idx++) { opcode_entry_type *fake_opcode; fake_opcode = (opcode_entry_type *) malloc (sizeof (opcode_entry_type)); fake_opcode->name = md_pseudo_table[idx].poc_name; fake_opcode->func = (void *) (md_pseudo_table + idx); fake_opcode->opcode = 250; hash_insert (opcode_hash_control, fake_opcode->name, fake_opcode); } linkrelax = 1;}struct z8k_exp { char *e_beg; char *e_end; expressionS e_exp;};typedef struct z8k_op { /* 'b','w','r','q'. */ char regsize; /* 0 .. 15. */ unsigned int reg; int mode; /* Any other register associated with the mode. */ unsigned int x_reg; /* Any expression. */ expressionS exp;} op_type;static expressionS *da_operand;static expressionS *imm_operand;int reg[16];int the_cc;int the_ctrl;int the_flags;int the_interrupt;char *whatreg (reg, src) int *reg; char *src;{ if (isdigit (src[1])) { *reg = (src[0] - '0') * 10 + src[1] - '0'; return src + 2; } else { *reg = (src[0] - '0'); return src + 1; }}/* Parse operands rh0-rh7, rl0-rl7 r0-r15 rr0-rr14 rq0--rq12 WREG r0,r1,r2,r3,r4,r5,r6,r7,fp,sp r0l,r0h,..r7l,r7h @WREG @WREG+ @-WREG #const*//* Try to parse a reg name. Return a pointer to the first character in SRC after the reg name. */char *parse_reg (src, mode, reg) char *src; int *mode; unsigned int *reg;{ char *res = 0; char regno; if (src[0] == 's' && src[1] == 'p') { if (segmented_mode) { *mode = CLASS_REG_LONG; *reg = 14; } else { *mode = CLASS_REG_WORD; *reg = 15; } return src + 2; } if (src[0] == 'r') { if (src[1] == 'r') { *mode = CLASS_REG_LONG; res = whatreg (reg, src + 2); regno = *reg; if (regno > 14) as_warn (_("register rr%d, out of range."), regno); } else if (src[1] == 'h') { *mode = CLASS_REG_BYTE; res = whatreg (reg, src + 2); regno = *reg; if (regno > 7) as_warn (_("register rh%d, out of range."), regno); } else if (src[1] == 'l') { *mode = CLASS_REG_BYTE; res = whatreg (reg, src + 2); regno = *reg; if (regno > 7) as_warn (_("register rl%d, out of range."), regno); *reg += 8; } else if (src[1] == 'q') { *mode = CLASS_REG_QUAD; res = whatreg (reg, src + 2); regno = *reg; if (regno > 12) as_warn (_("register rq%d, out of range."), regno); } else { *mode = CLASS_REG_WORD; res = whatreg (reg, src + 1); regno = *reg; if (regno > 15) as_warn (_("register r%d, out of range."), regno); } } return res;}char *parse_exp (s, op) char *s; expressionS *op;{ char *save = input_line_pointer; char *new; input_line_pointer = s; expression (op); if (op->X_op == O_absent) as_bad (_("missing operand")); new = input_line_pointer; input_line_pointer = save; return new;}/* The many forms of operand: <rb> <r> <rr> <rq> @r #exp exp exp(r) r(#exp) r(r) */static char *checkfor (ptr, what) char *ptr; char what;{ if (*ptr == what) ptr++; else as_bad (_("expected %c"), what); return ptr;}/* Make sure the mode supplied is the size of a word. */static voidregword (mode, string) int mode; char *string;{ int ok; ok = CLASS_REG_WORD; if (ok != mode) { as_bad (_("register is wrong size for a word %s"), string); }}/* Make sure the mode supplied is the size of an address. */static voidregaddr (mode, string) int mode; char *string;{ int ok; ok = segmented_mode ? CLASS_REG_LONG : CLASS_REG_WORD; if (ok != mode) { as_bad (_("register is wrong size for address %s"), string); }}struct ctrl_names { int value; char *name;};struct ctrl_names ctrl_table[] = { { 0x2, "fcw" }, { 0x3, "refresh" }, { 0x4, "psapseg" }, { 0x5, "psapoff" }, { 0x5, "psap" }, { 0x6, "nspseg" }, { 0x7, "nspoff" }, { 0x7, "nsp" }, { 0 , 0 }};static voidget_ctrl_operand (ptr, mode, dst) char **ptr; struct z8k_op *mode; unsigned int dst ATTRIBUTE_UNUSED;{ char *src = *ptr; int i; while (*src == ' ') src++; mode->mode = CLASS_CTRL; for (i = 0; ctrl_table[i].name; i++) { int j; for (j = 0; ctrl_table[i].name[j]; j++) { if (ctrl_table[i].name[j] != src[j]) goto fail; } the_ctrl = ctrl_table[i].value; *ptr = src + j; return; fail: ; } the_ctrl = 0; return;}struct flag_names { int value; char *name;};struct flag_names flag_table[] = { { 0x1, "p" }, { 0x1, "v" }, { 0x2, "s" }, { 0x4, "z" }, { 0x8, "c" }, { 0x0, "+" }, { 0, 0 }};static voidget_flags_operand (ptr, mode, dst) char **ptr; struct z8k_op *mode; unsigned int dst ATTRIBUTE_UNUSED;{ char *src = *ptr; int i; int j; while (*src == ' ') src++; mode->mode = CLASS_FLAGS; the_flags = 0; for (j = 0; j <= 9; j++) { if (!src[j]) goto done; for (i = 0; flag_table[i].name; i++) { if (flag_table[i].name[0] == src[j]) { the_flags = the_flags | flag_table[i].value; goto match; } } goto done; match: ; } done: *ptr = src + j; return;}struct interrupt_names { int value; char *name;};struct interrupt_names intr_table[] = { { 0x1, "nvi" }, { 0x2, "vi" }, { 0x3, "both" }, { 0x3, "all" }, { 0, 0 }};static voidget_interrupt_operand (ptr, mode, dst) char **ptr; struct z8k_op *mode; unsigned int dst ATTRIBUTE_UNUSED;{ char *src = *ptr; int i; while (*src == ' ') src++; mode->mode = CLASS_IMM; for (i = 0; intr_table[i].name; i++) { int j; for (j = 0; intr_table[i].name[j]; j++) { if (intr_table[i].name[j] != src[j]) goto fail; } the_interrupt = intr_table[i].value; *ptr = src + j; return; fail: ; } the_interrupt = 0x0; return;}struct cc_names { int value; char *name;};struct cc_names table[] = { { 0x0, "f" }, { 0x1, "lt" }, { 0x2, "le" }, { 0x3, "ule" }, { 0x4, "ov" }, { 0x4, "pe" }, { 0x5, "mi" }, { 0x6, "eq" }, { 0x6, "z" }, { 0x7, "c" }, { 0x7, "ult" }, { 0x8, "t" }, { 0x9, "ge" }, { 0xa, "gt" }, { 0xb, "ugt" }, { 0xc, "nov" }, { 0xc, "po" }, { 0xd, "pl" }, { 0xe, "ne" }, { 0xe, "nz" }, { 0xf, "nc" }, { 0xf, "uge" }, { 0 , 0 }};static voidget_cc_operand (ptr, mode, dst) char **ptr; struct z8k_op *mode; unsigned int dst ATTRIBUTE_UNUSED;{ char *src = *ptr; int i; while (*src == ' ') src++; mode->mode = CLASS_CC; for (i = 0; table[i].name; i++) { int j; for (j = 0; table[i].name[j]; j++) { if (table[i].name[j] != src[j]) goto fail; } the_cc = table[i].value; *ptr = src + j; return; fail: ; } the_cc = 0x8;}static voidget_operand (ptr, mode, dst) char **ptr; struct z8k_op *mode; unsigned int dst ATTRIBUTE_UNUSED;{ char *src = *ptr; char *end; mode->mode = 0; while (*src == ' ') src++; if (*src == '#') { mode->mode = CLASS_IMM; imm_operand = &(mode->exp); src = parse_exp (src + 1, &(mode->exp)); } else if (*src == '@') { int d; mode->mode = CLASS_IR; src = parse_reg (src + 1, &d, &mode->reg); } else { int regn; end = parse_reg (src, &mode->mode, ®n); if (end) { int nw, nr; src = end; if (*src == '(') { src++; end = parse_reg (src, &nw, &nr); if (end) { /* Got Ra(Rb). */ src = end; if (*src != ')') as_bad (_("Missing ) in ra(rb)")); else src++; regaddr (mode->mode, "ra(rb) ra");#if 0 regword (mode->mode, "ra(rb) rb");#endif mode->mode = CLASS_BX; mode->reg = regn; mode->x_reg = nr; reg[ARG_RX] = nr; } else { /* Got Ra(disp). */ if (*src == '#') src++; src = parse_exp (src, &(mode->exp)); src = checkfor (src, ')'); mode->mode = CLASS_BA; mode->reg = regn; mode->x_reg = 0; imm_operand = &(mode->exp); } } else { mode->reg = regn; mode->x_reg = 0; } } else { /* No initial reg. */ src = parse_exp (src, &(mode->exp)); if (*src == '(') { src++; end = parse_reg (src, &(mode->mode), ®n); regword (mode->mode, "addr(Ra) ra"); mode->mode = CLASS_X; mode->reg = regn; mode->x_reg = 0; da_operand = &(mode->exp); src = checkfor (end, ')'); } else { /* Just an address. */ mode->mode = CLASS_DA; mode->reg = 0; mode->x_reg = 0; da_operand = &(mode->exp); } } } *ptr = src;}static char *get_operands (opcode, op_end, operand) opcode_entry_type *opcode; char *op_end; op_type *operand;{ char *ptr = op_end; char *savptr; switch (opcode->noperands) { case 0: operand[0].mode = 0; operand[1].mode = 0; break; case 1: ptr++; if (opcode->arg_info[0] == CLASS_CC) { get_cc_operand (&ptr, operand + 0, 0); } else if (opcode->arg_info[0] == CLASS_FLAGS) { get_flags_operand (&ptr, operand + 0, 0); } else if (opcode->arg_info[0] == (CLASS_IMM + (ARG_IMM2))) { get_interrupt_operand (&ptr, operand + 0, 0); } else { get_operand (&ptr, operand + 0, 0); } operand[1].mode = 0; break; case 2: ptr++; savptr = ptr; if (opcode->arg_info[0] == CLASS_CC) { get_cc_operand (&ptr, operand + 0, 0); } else if (opcode->arg_info[0] == CLASS_CTRL) { get_ctrl_operand (&ptr, operand + 0, 0); if (the_ctrl == 0) { ptr = savptr; get_operand (&ptr, operand + 0, 0); if (ptr == 0) return NULL; if (*ptr == ',') ptr++; get_ctrl_operand (&ptr, operand + 1, 1); return ptr; } } else { get_operand (&ptr, operand + 0, 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -