📄 tc-h8300.c
字号:
/* tc-h8300.c -- Assemble code for the Hitachi H8/300 Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 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>. */#include <stdio.h>#include "as.h"#include "subsegs.h"#include "bfd.h"#define DEFINE_TABLE#define h8_opcodes ops#include "opcode/h8300.h"#include <ctype.h>const char comment_chars[] = ";";const char line_comment_chars[] = "#";const char line_separator_chars[] = "";/* 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 */void cons ();int Hmode;int Smode;#define PSIZE (Hmode ? L_32 : L_16)#define DMODE (L_16)#define DSYMMODE (Hmode ? L_24 : L_16)int bsize = L_8; /* default branch displacement */voidh8300hmode (){ Hmode = 1; Smode = 0;}voidh8300smode (){ Smode = 1; Hmode = 1;}voidsbranch (size) int size;{ bsize = size;}static voidpint (){ cons (Hmode ? 4 : 2);}const pseudo_typeS md_pseudo_table[] ={ {"h8300h", h8300hmode, 0}, {"h8300s", h8300smode, 0}, {"sbranch", sbranch, L_8}, {"lbranch", sbranch, L_16}, {"int", pint, 0}, {"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}, {0, 0, 0}};const int md_reloc_size;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";static struct hash_control *opcode_hash_control; /* Opcode mnemonics *//* This function is called once, at assembler startup time. This should set up all the tables, etc. that the MD part of the assembler needs. */voidmd_begin (){ struct h8_opcode *opcode; char prev_buffer[100]; int idx = 0; opcode_hash_control = hash_new (); prev_buffer[0] = 0; for (opcode = h8_opcodes; opcode->name; opcode++) { /* Strip off any . part when inserting the opcode and only enter unique codes into the hash table. */ char *src = opcode->name; unsigned int len = strlen (src); char *dst = malloc (len + 1); char *buffer = dst; opcode->size = 0; while (*src) { if (*src == '.') { src++; opcode->size = *src; break; } *dst++ = *src++; } *dst++ = 0; if (strcmp (buffer, prev_buffer)) { hash_insert (opcode_hash_control, buffer, (char *) opcode); strcpy (prev_buffer, buffer); idx++; } opcode->idx = idx; /* Find the number of operands. */ opcode->noperands = 0; while (opcode->args.nib[opcode->noperands] != E) opcode->noperands++; /* Find the length of the opcode in bytes. */ opcode->length = 0; while (opcode->data.nib[opcode->length * 2] != E) opcode->length++; } linkrelax = 1;}struct h8_exp{ char *e_beg; char *e_end; expressionS e_exp;};int dispreg;int opsize; /* Set when a register size is seen */struct h8_op{ op_type mode; unsigned reg; expressionS exp;};/* parse operands WREG r0,r1,r2,r3,r4,r5,r6,r7,fp,sp r0l,r0h,..r7l,r7h @WREG @WREG+ @-WREG #const ccr*//* Try to parse a reg name. Return the number of chars consumed. */static intparse_reg (src, mode, reg, direction) char *src; op_type *mode; unsigned int *reg; int direction;{ char *end; int len; /* Cribbed from get_symbol_end. */ if (!is_name_beginner (*src) || *src == '\001') return 0; end = src + 1; while (is_part_of_name (*end) || *end == '\001') end++; len = end - src; if (len == 2 && src[0] == 's' && src[1] == 'p') { *mode = PSIZE | REG | direction; *reg = 7; return len; } if (len == 3 && src[0] == 'c' && src[1] == 'c' && src[2] == 'r') { *mode = CCR; *reg = 0; return len; } if (len == 3 && src[0] == 'e' && src[1] == 'x' && src[2] == 'r') { *mode = EXR; *reg = 0; return len; } if (len == 2 && src[0] == 'f' && src[1] == 'p') { *mode = PSIZE | REG | direction; *reg = 6; return len; } if (len == 3 && src[0] == 'e' && src[1] == 'r' && src[2] >= '0' && src[2] <= '7') { *mode = L_32 | REG | direction; *reg = src[2] - '0'; if (!Hmode) as_warn (_("Reg not valid for H8/300")); return len; } if (len == 2 && src[0] == 'e' && src[1] >= '0' && src[1] <= '7') { *mode = L_16 | REG | direction; *reg = src[1] - '0' + 8; if (!Hmode) as_warn (_("Reg not valid for H8/300")); return len; } if (src[0] == 'r') { if (src[1] >= '0' && src[1] <= '7') { if (len == 3 && src[2] == 'l') { *mode = L_8 | REG | direction; *reg = (src[1] - '0') + 8; return len; } if (len == 3 && src[2] == 'h') { *mode = L_8 | REG | direction; *reg = (src[1] - '0'); return len; } if (len == 2) { *mode = L_16 | REG | direction; *reg = (src[1] - '0'); return len; } } } return 0;}static 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;}static char *skip_colonthing (ptr, exp, mode) char *ptr; expressionS *exp ATTRIBUTE_UNUSED; int *mode;{ if (*ptr == ':') { ptr++; *mode &= ~SIZE; if (*ptr == '8') { ptr++; /* ff fill any 8 bit quantity */ /* exp->X_add_number -= 0x100; */ *mode |= L_8; } else { if (*ptr == '2') { *mode |= L_24; } else if (*ptr == '3') { *mode |= L_32; } else if (*ptr == '1') { *mode |= L_16; } while (isdigit (*ptr)) ptr++; } } return ptr;}/* The many forms of operand: Rn Register direct @Rn Register indirect @(exp[:16], Rn) Register indirect with displacement @Rn+ @-Rn @aa:8 absolute 8 bit @aa:16 absolute 16 bit @aa absolute 16 bit #xx[:size] immediate data @(exp:[8], pc) pc rel @@aa[:8] memory indirect */char *colonmod24 (op, src) struct h8_op *op; char *src;{ int mode = 0; src = skip_colonthing (src, &op->exp, &mode); if (!mode) { /* Choose a default mode. */ if (op->exp.X_add_number < -32768 || op->exp.X_add_number > 32767) { if (Hmode) mode = L_24; else mode = L_16; } else if (op->exp.X_add_symbol || op->exp.X_op_symbol) mode = DSYMMODE; else mode = DMODE; } op->mode |= mode; return src;}static voidget_operand (ptr, op, dst, direction) char **ptr; struct h8_op *op; unsigned int dst ATTRIBUTE_UNUSED; int direction;{ char *src = *ptr; op_type mode; unsigned int num; unsigned int len; op->mode = E; /* Gross. Gross. ldm and stm have a format not easily handled by get_operand. We deal with it explicitly here. */ if (src[0] == 'e' && src[1] == 'r' && isdigit (src[2]) && src[3] == '-' && src[4] == 'e' && src[5] == 'r' && isdigit (src[6])) { int low, high; low = src[2] - '0'; high = src[6] - '0'; if (high < low) as_bad (_("Invalid register list for ldm/stm\n")); if (low % 2) as_bad (_("Invalid register list for ldm/stm\n")); if (high - low > 3) as_bad (_("Invalid register list for ldm/stm\n")); if (high - low != 1 && low % 4) as_bad (_("Invalid register list for ldm/stm\n")); /* Even sicker. We encode two registers into op->reg. One for the low register to save, the other for the high register to save; we also set the high bit in op->reg so we know this is "very special". */ op->reg = 0x80000000 | (high << 8) | low; op->mode = REG; *ptr = src + 7; return; } len = parse_reg (src, &op->mode, &op->reg, direction); if (len) { *ptr = src + len; return; } if (*src == '@') { src++; if (*src == '@') { src++; src = parse_exp (src, &op->exp); src = skip_colonthing (src, &op->exp, &op->mode); *ptr = src; op->mode = MEMIND; return; } if (*src == '-') { src++; len = parse_reg (src, &mode, &num, direction); if (len == 0) { /* Oops, not a reg after all, must be ordinary exp. */ src--; /* Must be a symbol. */ op->mode = ABS | PSIZE | direction; *ptr = skip_colonthing (parse_exp (src, &op->exp), &op->exp, &op->mode); return; } if ((mode & SIZE) != PSIZE) as_bad (_("Wrong size pointer register for architecture.")); op->mode = RDDEC; op->reg = num; *ptr = src + len; return; } if (*src == '(') { /* Disp. */ src++; /* Start off assuming a 16 bit offset. */ src = parse_exp (src, &op->exp); src = colonmod24 (op, src); if (*src == ')') { src++; op->mode |= ABS | direction; *ptr = src; return; } if (*src != ',') { as_bad (_("expected @(exp, reg16)")); return; } src++; len = parse_reg (src, &mode, &op->reg, direction); if (len == 0 || !(mode & REG)) { as_bad (_("expected @(exp, reg16)")); return; } op->mode |= DISP | direction; dispreg = op->reg; src += len; src = skip_colonthing (src, &op->exp, &op->mode);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -