/* tc-vax.c - vax-specific -
- Copyright 1987, 1991, 1992, 1993, 1994, 1995, 1998, 2000, 2001, 2002,
- 2003, 2004, 2005, 2006, 2007, 2008, 2009
- Free Software Foundation, Inc.
+ Copyright (C) 1987-2020 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
bbsc e4
bbcc e5
Always, you complement 0th bit to reverse condition.
- Always, 1-byte opcde, longword-address, byte-address, 1-byte-displacement
+ Always, 1-byte opcode, longword-address, byte-address, 1-byte-displacement
2c. J<cond> where cond tests low-order memory bit
length of byte,word,long.
#define BB (1+-128)
#define WF (2+ 32767)
#define WB (2+-32768)
-/* Dont need LF, LB because they always reach. [They are coded as 0.] */
+/* Don't need LF, LB because they always reach. [They are coded as 0.] */
#define C(a,b) ENCODE_RELAX(a,b)
/* This macro has no side-effects. */
#undef WB
void float_cons (int);
-int flonum_gen2vax (char, FLONUM_TYPE *, LITTLENUM_TYPE *);
+int flonum_gen2vax (int, FLONUM_TYPE *, LITTLENUM_TYPE *);
const pseudo_typeS md_pseudo_table[] =
{
{
valueT value = * valueP;
- if (((fixP->fx_addsy == NULL && fixP->fx_subsy == NULL)
- && fixP->fx_r_type != BFD_RELOC_32_PLT_PCREL
- && fixP->fx_r_type != BFD_RELOC_32_GOT_PCREL)
- || fixP->fx_r_type == NO_RELOC)
- number_to_chars_littleendian (fixP->fx_where + fixP->fx_frag->fr_literal,
- value, fixP->fx_size);
+ if (fixP->fx_subsy != (symbolS *) NULL)
+ as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
- if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
+ if (fixP->fx_addsy == NULL)
fixP->fx_done = 1;
+
+ if (fixP->fx_done)
+ number_to_chars_littleendian (fixP->fx_where + fixP->fx_frag->fr_literal,
+ value, fixP->fx_size);
+ else
+ /* Initialise the part of an instruction frag covered by the
+ relocation. (Many occurrences of frag_more followed by fix_new
+ lack any init of the frag.) Since VAX uses RELA relocs the
+ value we write into this field doesn't really matter. */
+ memset (fixP->fx_where + fixP->fx_frag->fr_literal, 0, fixP->fx_size);
}
/* Convert a number from VAX byte order (little endian)
ban these opcodes. They are mnemonics for "elastic" instructions
that are supposed to assemble into the fewest bytes needed to do a
branch, or to do a conditional branch, or whatever.
-
+
The opcode is in the usual place [low-order n*8 bits]. This means
that if you mask off the bucky bits, the usual rules apply about
how long the opcode is.
-
+
All VAX branch displacements come at the end of the instruction.
For simple branches (1-byte opcode + 1-byte displacement) the last
operand is coded 'b?' where the "data type" '?' is a clue that we
and branch around a jump. This is by far the most common case.
That is why the VIT_OPCODE_SYNTHETIC bit is set: it says this is
a 0-byte op-code followed by 2 or more bytes of operand address.
-
+
If the op-code has VIT_OPCODE_SPECIAL set, then we have a more unusual
case.
-
+
For JBSB & JBR the treatment is the similar, except (1) we have a 'bw'
option before (2) we can directly JSB/JMP because there is no condition.
These operands have 'b-' as their access/data type.
-
+
That leaves a bunch of random opcodes: JACBx, JxOBxxx. In these
cases, we do the same idea. JACBxxx are all marked with a 'b!'
JAOBxxx & JSOBxxx are marked with a 'b:'. */
/* Take 3 char.s, the last of which may be `\0` (non-existent)
and return the VAX register number that they represent.
-
+
Return -1 if they don't form a register name. Good names return
a number from 0:15 inclusive.
-
+
Case is not important in a name.
-
+
Register names understood are:
-
+
R0
R1
R2
For speed, expect a string of whitespace to be reduced to a single ' '.
This is the case for GNU AS, and is easy for other DEC-compatible
assemblers.
-
+
Knowledge about DEC VAX assembler operand notation lives here.
This doesn't even know what a register name is, except it believes
all register names are 2 or 3 characters, and lets vax_reg_parse() say
what number each name represents.
It does, however, know that PC, SP etc are special registers so it can
detect addressing modes that are silly for those registers.
-
+
Where possible, it delivers 1 fatal or 1 warning message if the operand
is suspect. Exactly what we test for is still evolving.
---
Arg block.
-
+
There were a number of 'mismatched argument type' bugs to vip_op.
The most general solution is to typedef each (of many) arguments.
We used instead a typedef'd argument block. This is less modular
on most engines, and seems to keep programmers happy. It will have
to be done properly if we ever want to use vip_op as a general-purpose
module (it was designed to be).
-
+
G^
Doesn't support DEC "G^" format operands. These always take 5 bytes
If there is some other use for "G^", feel free to code it in!
speed
-
+
If I nested if()s more, I could avoid testing (*err) which would save
time, space and page faults. I didn't nest all those if()s for clarity
and because I think the mode testing can be re-arranged 1st to test the
- commoner constructs 1st. Does anybody have statistics on this?
-
+ commoner constructs 1st. Does anybody have statistics on this?
+
error messages
-
+
In future, we should be able to 'compose' error messages in a scratch area
and give the user MUCH more informative error messages. Although this takes
a little more code at run-time, it will make this module much more self-
the Un*x characters "$`*", that most users will expect from this AS.
----
-
+
The input is a string, ending with '\0'.
-
+
We also require a 'hint' of what kind of operand is expected: so
we can remind caller not to write into literals for instance.
-
+
The output is a skeletal instruction.
-
+
The algorithm has two parts.
1. extract the syntactic features (parse off all the @^#-()+[] mode crud);
2. express the @^#-()+[] as some parameters suited to further analysis.
-
+
2nd step is where we detect the googles of possible invalid combinations
a human (or compiler) might write. Note that if we do a half-way
decent assembler, we don't know how long to make (eg) displacement
- error text(s) why we couldn't understand the operand
----
-
+
To decode output of this, test errtxt. If errtxt[0] == '\0', then
we had no errors that prevented parsing. Also, if we ever report
an internal bug, errtxt[0] is set non-zero. So one test tells you
if the other outputs are to be taken seriously.
----
-
+
Dec defines the semantics of address modes (and values)
by a two-letter code, explained here.
-
+
letter 1: access type
-
+
a address calculation - no data access, registers forbidden
b branch displacement
m read - let go of bus - write back "modify"
v bit field address: like 'a' but registers are OK
w write
space no operator (eg ".long foo") [our convention]
-
+
letter 2: data type (i.e. width, alignment)
-
+
b byte
d double precision floating point (D format)
f single precision floating point (F format)
? simple synthetic branch operand
- unconditional synthetic JSB/JSR operand
! complex synthetic branch operand
-
+
The '-?!' letter 2's are not for external consumption. They are used
for various assemblers. Generally, all unknown widths are assumed 0.
We don't limit your choice of width character.
-
+
DEC operands are hard work to parse. For example, '@' as the first
character means indirect (deferred) mode but elsewhere it is a shift
operator.
We try hard not to parse anything that MIGHT be part of the expression
buried in that syntax. For example if we see @...(Rn) we don't check
for '-' before the '(' because mode @-(Rn) does not exist.
-
+
After parsing we have:
-
+
at 1 if leading '@' (or Un*x '*')
len takes one value from " bilsw". eg B^ -> 'b'.
hash 1 if leading '#' (or Un*x '$')
paren 1 if () are around register
reg major register number 0:15 -1 means absent
ndx index register number 0:15 -1 means absent
-
+
Again, I dare not explain it: just trace ALL the code!
Summary of vip_op outputs.
get the types wrong below, we lose at compile time rather than at
lint or run time. */
char access_mode; /* vop_access. */
- char width; /* vop_width. */
access_mode = vopP->vop_access;
- width = vopP->vop_width;
/* None of our code bugs (yet), no user text errors, no warnings
even. */
err = wrn = 0;
/* p points to what may be the beginning of an expression.
We have peeled off the front all that is peelable.
We know at, len, hash.
-
+
Lets point q at the end of the text and parse that (backwards). */
for (q = p; *q; q++)
We will deliver a 4-bit reg, and a 4-bit mode. */
/* Case of branch operand. Different. No L^B^W^I^S^ allowed for instance.
-
+
in: at ?
len ?
hash ?
paren ?
reg ?
ndx ?
-
+
out: mode 0
reg -1
len ' '
/* Since nobody seems to use it: comment this 'feature'(?) out for now. */
#ifdef NEVER
/* Case of stand-alone operand. e.g. ".long foo"
-
+
in: at ?
len ?
hash ?
paren ?
reg ?
ndx ?
-
+
out: mode 0
reg -1
len ' '
#endif
/* Case of S^#.
-
+
in: at 0
len 's' definition
hash 1 demand
paren 0 by "()" scan logic because "S^" seen
reg -1 or nn by mistake
ndx -1
-
+
out: mode 0
reg -1
len 's'
err = _("S^# may only read-access");
}
}
-
+
/* Case of -(Rn), which is weird case.
-
+
in: at 0
len '
hash 0
paren 1 by definition
reg present by definition
ndx optional
-
+
out: mode 7
reg present
len ' '
}
/* Case of (Rn)+, which is slightly different.
-
+
in: at
len ' '
hash 0
paren 1 by definition
reg present by definition
ndx optional
-
+
out: mode 8+@
reg present
len ' '
}
/* Case of #, without S^.
-
+
in: at
len ' ' or 'i'
hash 1 by definition
paren 0
reg absent
ndx optional
-
+
out: mode 8+@
reg PC
len ' ' or 'i'
/* Case of Rn. We separate this one because it has a few special
errors the remaining modes lack.
-
+
in: at optional
len ' '
hash 0 by program logic
paren 0 by definition
reg present by definition
ndx optional
-
+
out: mode 5+@
reg present
len ' ' enforce no length
paren == 1 OR reg==-1 */
/* Rest of cases fit into one bunch.
-
+
in: at optional
len ' ' or 'b' or 'w' or 'l'
hash 0 by program logic
paren optional
reg optional
ndx optional
-
+
out: mode 10 + @ + len
reg optional
len ' ' or 'b' or 'w' or 'l'
{
case 'l':
mode += 2;
+ /* Fall through. */
case 'w':
mode += 2;
+ /* Fall through. */
case ' ': /* Assumed B^ until our caller changes it. */
case 'b':
break;
knowledge of how you parse (or evaluate) your expressions.
We do however strip off and decode addressing modes and operation
mnemonic.
-
+
The exploded instruction is returned to a struct vit of your choice.
#include "vax-inst.h" to know what a struct vit is.
-
+
This function's value is a string. If it is not "" then an internal
logic error was found: read this code to assign meaning to the string.
No argument string should generate such an error string:
it means a bug in our code, not in the user's text.
-
+
You MUST have called vip_begin() once before using this function. */
static void
if (*instring == ' ')
++instring;
-
+
/* MUST end in end-of-string or exactly 1 space. */
for (p = instring; *p && *p != ' '; p++)
;
default:
my_operand_length = 2;
- printf ("I dn't understand access width %c\n", mywidth);
+ printf ("I don't understand access width %c\n", mywidth);
break;
}
printf ("VAX assembler instruction operand: ");
size_t md_longopts_size = sizeof (md_longopts);
int
-md_parse_option (int c, char *arg)
+md_parse_option (int c, const char *arg)
{
switch (c)
{
if (fixp->fx_tcbit)
abort ();
- if (fixp->fx_r_type != BFD_RELOC_NONE)
+ if (fixp->fx_r_type != NO_RELOC)
{
code = fixp->fx_r_type;
#undef F
#undef MAP
- reloc = xmalloc (sizeof (arelent));
- reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+ reloc = XNEW (arelent);
+ reloc->sym_ptr_ptr = XNEW (asymbol *);
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
#ifndef OBJ_ELF
|| operandP->vop_access == 'a')
{
if (operandP->vop_access == 'v')
- as_warn (_("Invalid operand: immediate value used as base address."));
+ as_warn (_("Invalid operand: immediate value used as base address."));
else
- as_warn (_("Invalid operand: immediate value used as address."));
+ as_warn (_("Invalid operand: immediate value used as address."));
/* gcc 2.6.3 is known to generate these in at least
one case. */
}
}
}
-static char *vax_cons_special_reloc;
-
-void
+bfd_reloc_code_real_type
vax_cons (expressionS *exp, int size)
{
char *save;
+ const char *vax_cons_special_reloc;
SKIP_WHITESPACE ();
vax_cons_special_reloc = NULL;
}
if (vax_cons_special_reloc == NULL)
expression (exp);
+ else
+ switch (size)
+ {
+ case 1: return BFD_RELOC_8_PCREL;
+ case 2: return BFD_RELOC_16_PCREL;
+ case 4: return BFD_RELOC_32_PCREL;
+ }
+ return NO_RELOC;
}
/* This is called by emit_expr via TC_CONS_FIX_NEW when creating a
reloc for a cons. */
void
-vax_cons_fix_new (fragS *frag, int where, unsigned int nbytes, expressionS *exp)
+vax_cons_fix_new (fragS *frag, int where, unsigned int nbytes, expressionS *exp,
+ bfd_reloc_code_real_type r)
{
- bfd_reloc_code_real_type r;
-
- r = (nbytes == 1 ? BFD_RELOC_8 :
- (nbytes == 2 ? BFD_RELOC_16 : BFD_RELOC_32));
-
- if (vax_cons_special_reloc)
- {
- if (*vax_cons_special_reloc == 'p')
- {
- switch (nbytes)
- {
- case 1: r = BFD_RELOC_8_PCREL; break;
- case 2: r = BFD_RELOC_16_PCREL; break;
- case 4: r = BFD_RELOC_32_PCREL; break;
- default: abort ();
- }
- }
- }
+ if (r == NO_RELOC)
+ r = (nbytes == 1 ? BFD_RELOC_8
+ : nbytes == 2 ? BFD_RELOC_16
+ : BFD_RELOC_32);
fix_new_exp (frag, where, (int) nbytes, exp, 0, r);
- vax_cons_special_reloc = NULL;
}
-char *
+const char *
md_atof (int type, char * litP, int * sizeP)
{
return vax_md_atof (type, litP, sizeP);