📄 tc-w65.c
字号:
/* tc-w65.c -- Assemble code for the W65816 Copyright 1995, 1998, 2000, 2001 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 "bfd.h"#include "subsegs.h"#define DEFINE_TABLE#include "../opcodes/w65-opc.h"#include <ctype.h>const char comment_chars[] = "!";CONST char line_separator_chars[] = ";";const char line_comment_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 */#define OP_BCC 0x90#define OP_BCS 0xB0#define OP_BEQ 0xF0#define OP_BMI 0x30#define OP_BNE 0xD0#define OP_BPL 0x10#define OP_BRA 0x80#define OP_BRL 0x82#define OP_BVC 0x50#define OP_BVS 0x70void s_longa ();const pseudo_typeS md_pseudo_table[] = { {"int", cons, 2}, {"word", cons, 2}, {"longa", s_longa, 0}, {"longi", s_longa, 1}, {0, 0, 0}};void cons ();void s_align_bytes ();#if 0int md_reloc_size;#endifstatic int relax; /* set if -relax seen */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;int M; /* M flag */int X; /* X flag */#define C(a,b) ENCODE_RELAX(a,b)#define ENCODE_RELAX(what,length) (((what) << 2) + (length))#define GET_WHAT(x) ((x>>2))#define BYTE_DISP 1#define WORD_DISP 2#define UNDEF_BYTE_DISP 0#define UNDEF_WORD_DISP 3#define COND_BRANCH 1#define UNCOND_BRANCH 2#define END 3#define BYTE_F 127 /* How far we can branch forwards */#define BYTE_B -126 /* How far we can branch backwards */#define WORD_F 32767#define WORD_B 32768relax_typeS md_relax_table[C (END, 0)] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, /* COND_BRANCH */ { 0, 0, 0, 0 }, /* UNDEF_BYTE_DISP */ { BYTE_F, BYTE_B, 2, C (COND_BRANCH, WORD_DISP) }, /* BYTE_DISP */ { WORD_F, WORD_B, 5, 0 }, /* WORD_DISP */ { 0, 0, 5, 0 }, /* UNDEF_WORD_DISP */ /* UNCOND_BRANCH */ { 0, 0, 0, 0 }, /* UNDEF_BYTE_DISP */ { BYTE_F, BYTE_B, 2, C (UNCOND_BRANCH, WORD_DISP) }, /* BYTE_DISP */ { WORD_F, WORD_B, 3, 0 }, /* WORD_DISP */ { 0, 0, 3, 0 } /* UNDEF_WORD_DISP */};/* 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. */voids_longa (xmode){ int *p = xmode ? &X : &M; while (*input_line_pointer == ' ') input_line_pointer++; if (strncmp (input_line_pointer, "on", 2) == 0) { input_line_pointer += 2; *p = 0; } else if (strncmp (input_line_pointer, "off", 3) == 0) { *p = 1; input_line_pointer += 3; } else as_bad (_("need on or off.")); demand_empty_rest_of_line ();}voidmd_begin (){ struct opinfo *opcode; char *prev_name = ""; opcode_hash_control = hash_new (); /* Insert unique names into hash table. */ for (opcode = optable; opcode->name; opcode++) { if (strcmp (prev_name, opcode->name)) { prev_name = opcode->name; hash_insert (opcode_hash_control, opcode->name, (char *) opcode); } else { /* Make all the opcodes with the same name point to the same string. */ opcode->name = prev_name; } } flag_signed_overflow_ok = 1;}static expressionS immediate; /* absolute expression */static expressionS immediate1; /* absolute expression */static symbolS *dot (){ const char *fake; /* JF: '.' is pseudo symbol with value of current location in current segment. */ fake = FAKE_LABEL_NAME; return symbol_new (fake, now_seg, (valueT) frag_now_fix (), frag_now);}int expr_size;int expr_shift;int tc_cons_reloc;voidw65_expression (dest, bytes) expressionS *dest; unsigned int bytes;{ expr_size = 0; expr_shift = 0; tc_cons_reloc = 0; while (*input_line_pointer == ' ') input_line_pointer++; if (*input_line_pointer == '<') { expr_size = 1; input_line_pointer++; } else if (*input_line_pointer == '>') { expr_shift = 1; input_line_pointer++; } else if (*input_line_pointer == '^') { expr_shift = 2; input_line_pointer++; } expr (0, dest);}int amode;static char *parse_exp (s, bytes) char *s; int bytes;{ char *save; char *new; save = input_line_pointer; input_line_pointer = s; w65_expression (&immediate, bytes); if (immediate.X_op == O_absent) as_bad (_("missing operand")); new = input_line_pointer; input_line_pointer = save; return new;}static char *get_operands (info, ptr) struct opinfo *info; char *ptr;{ register int override_len = 0; register int bytes = 0; while (*ptr == ' ') ptr++; if (ptr[0] == '#') { ptr++; switch (info->amode) { case ADDR_IMMTOI: bytes = X ? 1 : 2; amode = ADDR_IMMTOI; break; case ADDR_IMMTOA: bytes = M ? 1 : 2; amode = ADDR_IMMTOA; break; case ADDR_IMMCOP: bytes = 1; amode = ADDR_IMMCOP; break; case ADDR_DIR: bytes = 2; amode = ADDR_ABS; break; default: abort (); break; } ptr = parse_exp (ptr); } else if (ptr[0] == '!') { ptr = parse_exp (ptr + 1); if (ptr[0] == ',') { if (ptr[1] == 'y') { amode = ADDR_ABS_IDX_Y; bytes = 2; ptr += 2; } else if (ptr[1] == 'x') { amode = ADDR_ABS_IDX_X; bytes = 2; ptr += 2; } else { as_bad (_("syntax error after <exp")); } } else { amode = ADDR_ABS; bytes = 2; } } else if (ptr[0] == '>') { ptr = parse_exp (ptr + 1); if (ptr[0] == ',' && ptr[1] == 'x') { amode = ADDR_ABS_LONG_IDX_X; bytes = 3; ptr += 2; } else { amode = ADDR_ABS_LONG; bytes = 3; } } else if (ptr[0] == '<') { ptr = parse_exp (ptr + 1); if (ptr[0] == ',') { if (ptr[1] == 'y') { amode = ADDR_DIR_IDX_Y; ptr += 2; bytes = 2; } else if (ptr[1] == 'x') { amode = ADDR_DIR_IDX_X; ptr += 2; bytes = 2; } else { as_bad (_("syntax error after <exp")); } } else { amode = ADDR_DIR; bytes = 1; } } else if (ptr[0] == 'a') { amode = ADDR_ACC; } else if (ptr[0] == '(') { /* Look for (exp),y (<exp),y (exp,x) (<exp,x) (exp) (!exp) (exp) (<exp) (exp,x) (!exp,x) (exp,s) (exp,s),y */ ptr++; if (ptr[0] == '<') { override_len = 1; ptr++; } else if (ptr[0] == '!') { override_len = 2; ptr++; } else if (ptr[0] == '>') { override_len = 3; ptr++; } else { override_len = 0; } ptr = parse_exp (ptr); if (ptr[0] == ',') { ptr++; if (ptr[0] == 'x' && ptr[1] == ')') { ptr += 2; if (override_len == 1) { amode = ADDR_DIR_IDX_IND_X; bytes = 2; } else { amode = ADDR_ABS_IND_IDX; bytes = 2; } } else if (ptr[0] == 's' && ptr[1] == ')' && ptr[2] == ',' && ptr[3] == 'y') { amode = ADDR_STACK_REL_INDX_IDX; bytes = 1; ptr += 4; } } else if (ptr[0] == ')') { if (ptr[1] == ',' && ptr[2] == 'y') { amode = ADDR_DIR_IND_IDX_Y; ptr += 3; bytes = 2; } else { if (override_len == 1) { amode = ADDR_DIR_IND; bytes = 1; } else { amode = ADDR_ABS_IND; bytes = 2; } ptr++; } } } else if (ptr[0] == '[') { ptr = parse_exp (ptr + 1); if (ptr[0] == ']') { ptr++; if (ptr[0] == ',' && ptr[1] == 'y') { bytes = 1; amode = ADDR_DIR_IND_IDX_Y_LONG; ptr += 2; } else { if (info->code == O_jmp) { bytes = 2; amode = ADDR_ABS_IND_LONG; } else { bytes = 1; amode = ADDR_DIR_IND_LONG; } } } } else { ptr = parse_exp (ptr, 2); if (ptr[0] == ',') { if (ptr[1] == 'y') { if (override_len == 1) { bytes = 1; amode = ADDR_DIR_IDX_Y; } else { amode = ADDR_ABS_IDX_Y; bytes = 2; } ptr += 2; } else if (ptr[1] == 'x') { if (override_len == 1) { amode = ADDR_DIR_IDX_X; bytes = 1; } else { amode = ADDR_ABS_IDX_X; bytes = 2; } ptr += 2; } else if (ptr[1] == 's') { bytes = 1; amode = ADDR_STACK_REL; ptr += 2; } else { bytes = 1; immediate1 = immediate; ptr = parse_exp (ptr + 1); amode = ADDR_BLOCK_MOVE; } } else { switch (info->amode) { case ADDR_PC_REL: amode = ADDR_PC_REL; bytes = 1; break; case ADDR_PC_REL_LONG: amode = ADDR_PC_REL_LONG; bytes = 2; break; default: if (override_len == 1) { amode = ADDR_DIR; bytes = 1; } else if (override_len == 3) { bytes = 3; amode = ADDR_ABS_LONG; } else { amode = ADDR_ABS; bytes = 2; } } } } switch (bytes) { case 1: switch (expr_shift) { case 0: if (amode == ADDR_DIR) tc_cons_reloc = R_W65_DP; else tc_cons_reloc = R_W65_ABS8; break; case 1: tc_cons_reloc = R_W65_ABS8S8; break; case 2: tc_cons_reloc = R_W65_ABS8S16; break; } break; case 2: switch (expr_shift) { case 0: tc_cons_reloc = R_W65_ABS16; break; case 1: tc_cons_reloc = R_W65_ABS16S8; break; case 2: tc_cons_reloc = R_W65_ABS16S16; break; } } return ptr;}/* Passed a pointer to a list of opcodes which use different addressing modes, return the opcode which matches the opcodes provided. */static struct opinfo *get_specific (opcode) struct opinfo *opcode;{ int ocode = opcode->code;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -