📄 m68k.c
字号:
/* m68k.c All the m68020 specific stuff in one convenient, huge, slow to compile, easy to find file. Copyright (C) 1987 Free Software Foundation, Inc.This file is part of GAS, the GNU Assembler.GAS is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 1, 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GAS; see the file COPYING. If not, write tothe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */#include <ctype.h>#include "m68k-opcode.h"#include "as.h"#include "obstack.h"#include "frags.h"#include "struc-symbol.h"#include "flonum.h"#include "expr.h"#include "hash.h"#include "md.h"#include "m68k.h"#ifdef M_SUN/* This variable contains the value to write out at the beginning of the a.out file. The 2<<16 means that this is a 68020 file instead of an old-style 68000 file */long omagic = 2<<16|OMAGIC; /* Magic byte for header file */#elselong omagic = OMAGIC;#endif/* This array holds the chars that always start a comment. If the pre-processor is disabled, these aren't very useful */const char comment_chars[] = "|";/* This array holds the chars that only start a comment at the beginning of a line. If the line seems to have the form '# 123 filename' .line and .file directives will appear in the pre-processed output *//* Note that input_file.c hand checks for '#' at the beginning of the first line of the input file. This is because the compiler outputs #NO_APP at the beginning of its output. *//* Also note that '/*' will always start a comment */const char line_comment_chars[] = "#";/* Chars that can be used to separate mant from exp in floating point nums */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[] = "rRsSfFdDxXeEpP";/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be changed in read.c . Ideally it shouldn't have to know about it at all, but nothing is ideal around here. */void fix_new();void install_operand();void install_gen_operand();/* Its an arbitrary name: This means I don't approve of it *//* See flames below */struct obstack robyn;#define TAB(x,y) (((x)<<2)+(y))#define TABTYPE(xy) ((xy) >> 2)#define BYTE 0#define SHORT 1#define LONG 2#define SZ_UNDEF 3#define BRANCH 1#define FBRANCH 2#define PCREL 3#define BCC68000 4#define DBCC 5#define PCLEA 6/* BCC68000 is for patching in an extra jmp instruction for long offsets on the 68000. The 68000 doesn't support long branches with branchs *//* This table desribes how you change sizes for the various types of variable size expressions. This version only supports two kinds. *//* Note that calls to frag_var need to specify the maximum expansion needed *//* This is currently 10 bytes for DBCC *//* The fields are: How far Forward this mode will reach: How far Backward this mode will reach: How many bytes this mode will add to the size of the frag Which mode to go to if the offset won't fit in this one */const relax_typeSmd_relax_table[] = {{ 1, 1, 0, 0 }, /* First entries aren't used */{ 1, 1, 0, 0 }, /* For no good reason except */{ 1, 1, 0, 0 }, /* that the VAX doesn't either */{ 1, 1, 0, 0 },{ (127), (-128), 0, TAB(BRANCH,SHORT)},{ (32767), (-32768), 2, TAB(BRANCH,LONG) },{ 0, 0, 4, 0 },{ 1, 1, 0, 0 },{ 1, 1, 0, 0 }, /* FBRANCH doesn't come BYTE */{ (32767), (-32768), 2, TAB(FBRANCH,LONG)},{ 0, 0, 4, 0 },{ 1, 1, 0, 0 },{ 1, 1, 0, 0 }, /* PCREL doesn't come BYTE */{ (32767), (-32768), 2, TAB(PCREL,LONG)},{ 0, 0, 4, 0 },{ 1, 1, 0, 0 },{ (127), (-128), 0, TAB(BCC68000,SHORT)},{ (32767), (-32768), 2, TAB(BCC68000,LONG) },{ 0, 0, 6, 0 }, /* jmp long space */{ 1, 1, 0, 0 },{ 1, 1, 0, 0 }, /* DBCC doesn't come BYTE */{ (32767), (-32768), 2, TAB(DBCC,LONG) },{ 0, 0, 10, 0 }, /* bra/jmp long space */{ 1, 1, 0, 0 },{ 1, 1, 0, 0 }, /* PCLEA doesn't come BYTE */{ 32767, -32768, 2, TAB(PCLEA,LONG) },{ 0, 0, 6, 0 },{ 1, 1, 0, 0 },};void s_data1(), s_data2(), s_even(), s_space();void s_proc(), float_cons();/* These are the machine dependent pseudo-ops. These are included so the assembler can work on the output from the SUN C compiler, which generates these. *//* 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[] = { { "data1", s_data1, 0 }, { "data2", s_data2, 0 }, { "even", s_even, 0 }, { "skip", s_space, 0 }, { "proc", s_proc, 0 }, { 0, 0, 0 }};/* #define isbyte(x) ((x)>=-128 && (x)<=127) *//* #define isword(x) ((x)>=-32768 && (x)<=32767) */#define issbyte(x) ((x)>=-128 && (x)<=127)#define isubyte(x) ((x)>=0 && (x)<=255)#define issword(x) ((x)>=-32768 && (x)<=32767)#define isuword(x) ((x)>=0 && (x)<=65535)#define isbyte(x) ((x)>=-128 && (x)<=255)#define isword(x) ((x)>=-32768 && (x)<=65535)#define islong(x) (1)extern char *input_line_pointer;/* Operands we can parse: (And associated modes)numb: 8 bit numnumw: 16 bit numnuml: 32 bit numdreg: data reg 0-7reg: address or data registerareg: address registerapc: address register, PC, ZPC or empty stringnum: 16 or 32 bit numnum2: like numsz: w or l if omitted, l assumedscale: 1 2 4 or 8 if omitted, 1 assumed7.4 IMMED #num --> NUM0.? DREG dreg --> dreg1.? AREG areg --> areg2.? AINDR areg@ --> *(areg)3.? AINC areg@+ --> *(areg++)4.? ADEC areg@- --> *(--areg)5.? AOFF apc@(numw) --> *(apc+numw) -- empty string and ZPC not allowed here6.? AINDX apc@(num,reg:sz:scale) --> *(apc+num+reg*scale)6.? AINDX apc@(reg:sz:scale) --> same, with num=06.? APODX apc@(num)@(num2,reg:sz:scale) --> *(*(apc+num)+num2+reg*scale)6.? APODX apc@(num)@(reg:sz:scale) --> same, with num2=06.? AMIND apc@(num)@(num2) --> *(*(apc+num)+num2) (previous mode without an index reg)6.? APRDX apc@(num,reg:sz:scale)@(num2) --> *(*(apc+num+reg*scale)+num2)6.? APRDX apc@(reg:sz:scale)@(num2) --> same, with num=07.0 ABSL num:sz --> *(num) num --> *(num) (sz L assumed)*** MSCR otherreg --> MagicWith -l option5.? AOFF apc@(num) --> *(apc+num) -- empty string and ZPC not allowed here stillexamples: #foo #0x35 #12 d2 a4 a3@ a5@+ a6@- a2@(12) pc@(14) a1@(5,d2:w:1) @(45,d6:l:4) pc@(a2) @(d4) etc . . .#name@(numw) -->turn into PC rel modeapc@(num8,reg:sz:scale) --> *(apc+num8+reg*scale)*/#define IMMED 1#define DREG 2#define AREG 3#define AINDR 4#define ADEC 5#define AINC 6#define AOFF 7#define AINDX 8#define APODX 9#define AMIND 10#define APRDX 11#define ABSL 12#define MSCR 13#define REGLST 14#define FAIL 0#define OK 1/* DATA and ADDR have to be contiguous, so that reg-DATA gives 0-7==data reg, 8-15==addr reg for operands that take both types */#define DATA 1 /* 1- 8 == data registers 0-7 */#define ADDR (DATA+8) /* 9-16 == address regs 0-7 */#define FPREG (ADDR+8) /* 17-24 Eight FP registers */#define COPNUM (FPREG+8) /* 25-32 Co-processor #1-#8 */#define PC (COPNUM+8) /* 33 Program counter */#define ZPC (PC+1) /* 34 Hack for Program space, but 0 addressing */#define SR (ZPC+1) /* 35 Status Reg */#define CCR (SR+1) /* 36 Condition code Reg *//* These have to be in order for the movec instruction to work. */#define USP (CCR+1) /* 37 User Stack Pointer */#define ISP (USP+1) /* 38 Interrupt stack pointer */#define SFC (ISP+1) /* 39 */#define DFC (SFC+1) /* 40 */#define CACR (DFC+1) /* 41 */#define VBR (CACR+1) /* 42 */#define CAAR (VBR+1) /* 43 */#define MSP (CAAR+1) /* 44 */#define FPI (MSP+1) /* 45 */#define FPS (FPI+1) /* 46 */#define FPC (FPS+1) /* 47 *//* * these defines should be in m68k.c but * i put them here to keep all the m68851 stuff * together -rab * JF--Make sure these #s don't clash with the ones in m68k.c * That would be BAD. */#define TC (FPC+1) /* 48 */#define DRP (TC+1) /* 49 */#define SRP (DRP+1) /* 50 */#define CRP (SRP+1) /* 51 */#define CAL (CRP+1) /* 52 */#define VAL (CAL+1) /* 53 */#define SCC (VAL+1) /* 54 */#define AC (SCC+1) /* 55 */#define BAD (AC+1) /* 56,57,58,59, 60,61,62,63 */#define BAC (BAD+8) /* 64,65,66,67, 68,69,70,71 */#define PSR (BAC+8) /* 72 */#define PCSR (PSR+1) /* 73 *//* Note that COPNUM==processor #1 -- COPNUM+7==#8, which stores as 000 *//* I think. . . */#define SP ADDR+7/* JF these tables here are for speed at the expense of size *//* You can replace them with the #if 0 versions if you really need space and don't mind it running a bit slower */static char mklower_table[256];#define mklower(c) (mklower_table[(unsigned char)(c)])static char notend_table[256];static char alt_notend_table[256];#define notend(s) ( !(notend_table[(unsigned char)(*s)] || (*s==':' &&\ alt_notend_table[(unsigned char)(s[1])])))#if 0#define mklower(c) (isupper(c) ? tolower(c) : c)#endifstruct m68k_exp { char *e_beg; char *e_end; expressionS e_exp; short e_siz; /* 0== default 1==short/byte 2==word 3==long */};/* Internal form of an operand. */struct m68k_op { char *error; /* Couldn't parse it */ int mode; /* What mode this instruction is in. */ unsigned long int reg; /* Base register */ struct m68k_exp *con1; int ireg; /* Index register */ int isiz; /* 0==unspec 1==byte(?) 2==short 3==long */ int imul; /* Multipy ireg by this (1,2,4,or 8) */ struct m68k_exp *con2;};/* internal form of a 68020 instruction */struct m68_it { char *error; char *args; /* list of opcode info */ int numargs; int numo; /* Number of shorts in opcode */ short opcode[11]; struct m68k_op operands[6]; int nexp; /* number of exprs in use */ struct m68k_exp exprs[4]; int nfrag; /* Number of frags we have to produce */ struct { int fragoff; /* Where in the current opcode[] the frag ends */ symbolS *fadd; long int foff; int fragty; } fragb[4]; int nrel; /* Num of reloc strucs in use */ struct { int n; symbolS *add, *sub; long int off; char wid; char pcrel; } reloc[5]; /* Five is enough??? */};struct m68_it the_ins; /* the instruction being assembled *//* Macros for adding things to the m68_it struct */#define addword(w) the_ins.opcode[the_ins.numo++]=(w)/* Like addword, but goes BEFORE general operands */#define insop(w) {int z;\ for(z=the_ins.numo;z>opcode->m_codenum;--z)\ the_ins.opcode[z]=the_ins.opcode[z-1];\ for(z=0;z<the_ins.nrel;z++)\ the_ins.reloc[z].n+=2;\ the_ins.opcode[opcode->m_codenum]=w;\ the_ins.numo++;\}#define add_exp(beg,end) (\ the_ins.exprs[the_ins.nexp].e_beg=beg,\ the_ins.exprs[the_ins.nexp].e_end=end,\ &the_ins.exprs[the_ins.nexp++]\)/* The numo+1 kludge is so we can hit the low order byte of the prev word. Blecch*/#define add_fix(width,exp,pc_rel) {\ the_ins.reloc[the_ins.nrel].n= ((width)=='B') ? (the_ins.numo*2-1) : \ (((width)=='b') ? ((the_ins.numo-1)*2) : (the_ins.numo*2));\ the_ins.reloc[the_ins.nrel].add=adds((exp));\ the_ins.reloc[the_ins.nrel].sub=subs((exp));\ the_ins.reloc[the_ins.nrel].off=offs((exp));\ the_ins.reloc[the_ins.nrel].wid=width;\ the_ins.reloc[the_ins.nrel++].pcrel=pc_rel;\}#define add_frag(add,off,type) {\ the_ins.fragb[the_ins.nfrag].fragoff=the_ins.numo;\ the_ins.fragb[the_ins.nfrag].fadd=add;\ the_ins.fragb[the_ins.nfrag].foff=off;\ the_ins.fragb[the_ins.nfrag++].fragty=type;\}#define isvar(exp) ((exp) && (adds(exp) || subs(exp)))#define seg(exp) ((exp)->e_exp.X_seg)#define adds(exp) ((exp)->e_exp.X_add_symbol)#define subs(exp) ((exp)->e_exp.X_subtract_symbol)#define offs(exp) ((exp)->e_exp.X_add_number)struct m68_incant { char *m_operands; unsigned long m_opcode; short m_opnum; short m_codenum; struct m68_incant *m_next;};#define getone(x) ((((x)->m_opcode)>>16)&0xffff)#define gettwo(x) (((x)->m_opcode)&0xffff)/* JF modified this to handle cases where the first part of a symbol name looks like a register */intm68k_reg_parse(ccp)register char **ccp;{ register char c1, c2, c3, c4; register int n = 0, ret = FAIL; c1=mklower(ccp[0][0]);#ifdef REGISTER_PREFIX if(c1!=REGISTER_PREFIX) return FAIL; c1=mklower(ccp[0][1]); c2=mklower(ccp[0][2]); c3=mklower(ccp[0][3]); c4=mklower(ccp[0][4]);#else c2=mklower(ccp[0][1]); c3=mklower(ccp[0][2]); c4=mklower(ccp[0][3]);#endif switch(c1) { case 'a': if(c2>='0' && c2<='7') { n=2; ret=ADDR+c2-'0'; }#ifdef m68851 else if (c2 == 'c') { n = 2; ret = AC; }#endif break;#ifdef m68851 case 'b': if (c2 == 'a') { if (c3 == 'd') { if (c4 >= '0' && c4 <= '7') { n = 4; ret = BAD + c4 - '0'; } } if (c3 == 'c') { if (c4 >= '0' && c4 <= '7') { n = 4; ret = BAC + c4 - '0'; } } } break;#endif case 'c':#ifdef m68851 if (c2 == 'a' && c3 == 'l') { n = 3; ret = CAL; } else#endif /* This supports both CCR and CC as the ccr reg. */ if(c2=='c' && c3=='r') { n=3; ret = CCR; } else if(c2=='c') { n=2; ret = CCR; } else if(c2=='a' && (c3=='a' || c3=='c') && c4=='r') { n=4; ret = c3=='a' ? CAAR : CACR; }#ifdef m68851 else if (c2 == 'r' && c3 == 'p') { n = 3; ret = (CRP); }#endif break; case 'd': if(c2>='0' && c2<='7') { n=2; ret = DATA+c2-'0'; } else if(c2=='f' && c3=='c') { n=3; ret = DFC; }#ifdef m68851 else if (c2 == 'r' && c3 == 'p') { n = 3; ret = (DRP); }#endif break; case 'f': if(c2=='p') { if(c3>='0' && c3<='7') { n=3; ret = FPREG+c3-'0'; if(c4==':') ccp[0][3]=','; } else if(c3=='i') { n=3; ret = FPI; } else if(c3=='s') { n= (c4 == 'r' ? 4 : 3); ret = FPS; } else if(c3=='c') { n= (c4 == 'r' ? 4 : 3); ret = FPC; } } break; case 'i': if(c2=='s' && c3=='p') { n=3; ret = ISP; } break; case 'm': if(c2=='s' && c3=='p') { n=3; ret = MSP; } break; case 'p': if(c2=='c') {#ifdef m68851 if(c3 == 's' && c4=='r') { n=4; ret = (PCSR); } else#endif { n=2; ret = PC; } }#ifdef m68851 else if (c2 == 's' && c3 == 'r') {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -