#include "as.h"
#include "safe-ctype.h"
#include "subsegs.h"
#include "dwarf2dbg.h"
#include "tc-maxq.h"
#include "opcode/maxq.h"
#include "ctype.h"
#ifndef MAXQ10S
#define MAXQ10S 1
#endif
#ifndef _STRING_H
#include "string.h"
#endif
#ifndef DEFAULT_ARCH
#define DEFAULT_ARCH "MAXQ20"
#endif
#ifndef MAX_OPERANDS
#define MAX_OPERANDS 2
#endif
#ifndef MAX_MNEM_SIZE
#define MAX_MNEM_SIZE 8
#endif
#ifndef END_OF_INSN
#define END_OF_INSN '\0'
#endif
#ifndef IMMEDIATE_PREFIX
#define IMMEDIATE_PREFIX '#'
#endif
#ifndef MAX_REG_NAME_SIZE
#define MAX_REG_NAME_SIZE 4
#endif
#ifndef MAX_MEM_NAME_SIZE
#define MAX_MEM_NAME_SIZE 9
#endif
#define PFX0 0x0b
unsigned int max_version = bfd_mach_maxq20;
const char *default_arch = DEFAULT_ARCH;
union _maxq20_op
{
const reg_entry * reg;
char imms;
expressionS * disps;
symbolS * data;
const mem_access * mem;
int flag;
const reg_bit * r_bit;
};
typedef union _maxq20_op maxq20_opcode;
#ifdef BFD_ASSEMBLER
#define LONG_PREFIX MAXQ_LONGJUMP
#define SHORT_PREFIX MAXQ_SHORTJUMP
#define ABSOLUTE_ADDR_FOR_DATA MAXQ_INTERSEGMENT
#define NO_PREFIX 0
#define EXPLICT_LONG_PREFIX 14
#else
#define EXPLICT_LONG_PREFIX 14
#define LONG_PREFIX 5
#define SHORT_PREFIX 1
#define ABSOLUTE_ADDR_FOR_DATA 0
#define NO_PREFIX 0
#endif
typedef struct _maxq20_insn
{
MAXQ20_OPCODE_INFO op;
unsigned int operands;
unsigned int reg_operands, mem_operands, disp_operands, data_operands;
unsigned int imm_operands, imm_bit_operands, bit_operands, flag_operands;
UNKNOWN_OP types[MAX_OPERANDS];
int reloc[MAX_OPERANDS];
maxq20_opcode maxq20_op[MAX_OPERANDS];
int prefix;
unsigned char Instr_Prefix;
unsigned char instr[2];
}
maxq20_insn;
const char *extra_symbol_chars = "@(#";
const char comment_chars[] = ";";
const char line_comment_chars[] = ";#";
const char line_separator_chars[] = "";
const char *md_shortopts = "q";
const char EXP_CHARS[] = "eE";
const char FLT_CHARS[] = "";
#define OPTION_EB (OPTION_MD_BASE + 0)
#define OPTION_EL (OPTION_MD_BASE + 1)
#define MAXQ_10 (OPTION_MD_BASE + 2)
#define MAXQ_20 (OPTION_MD_BASE + 3)
struct option md_longopts[] =
{
{"MAXQ10", no_argument, NULL, MAXQ_10},
{"MAXQ20", no_argument, NULL, MAXQ_20},
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof (md_longopts);
symbolS *
md_undefined_symbol (char * name ATTRIBUTE_UNUSED)
{
return NULL;
}
static void
maxq_target (int target)
{
max_version = target;
bfd_set_arch_mach (stdoutput, bfd_arch_maxq, max_version);
}
int
md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
{
switch (c)
{
case MAXQ_10:
max_version = bfd_mach_maxq10;
break;
case MAXQ_20:
max_version = bfd_mach_maxq20;
break;
default:
return 0;
}
return 1;
}
void
md_show_usage (FILE * stream)
{
fprintf (stream, _(" MAXQ-specific assembler options:\n"));
fprintf (stream, _("\
-MAXQ20 generate obj for MAXQ20(default)\n\
-MAXQ10 generate obj for MAXQ10\n\
"));
}
#ifdef BFD_ASSEMBLER
unsigned long
maxq20_mach (void)
{
if (!(strcmp (default_arch, "MAXQ20")))
return 0;
as_fatal (_("Unknown architecture"));
return 1;
}
arelent *
tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
{
arelent *rel;
bfd_reloc_code_real_type code;
switch (fixp->fx_r_type)
{
case MAXQ_INTERSEGMENT:
case MAXQ_LONGJUMP:
case BFD_RELOC_16_PCREL_S2:
code = fixp->fx_r_type;
break;
case 0:
default:
switch (fixp->fx_size)
{
default:
as_bad_where (fixp->fx_file, fixp->fx_line,
_("can not do %d byte relocation"), fixp->fx_size);
code = BFD_RELOC_32;
break;
case 1:
code = BFD_RELOC_8;
break;
case 2:
code = BFD_RELOC_16;
break;
case 4:
code = BFD_RELOC_32;
break;
}
}
rel = xmalloc (sizeof (arelent));
rel->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
*rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
rel->addend = fixp->fx_addnumber;
rel->howto = bfd_reloc_type_lookup (stdoutput, code);
if (rel->howto == NULL)
{
as_bad_where (fixp->fx_file, fixp->fx_line,
_("cannot represent relocation type %s"),
bfd_get_reloc_code_name (code));
rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
assert (rel->howto != NULL);
}
return rel;
}
#endif
int
md_estimate_size_before_relax (fragS *fragP, segT segment)
{
if ((S_GET_SEGMENT (fragP->fr_symbol) != segment)
|| fragP->fr_subtype == EXPLICT_LONG_PREFIX)
{
RELOC_ENUM reloc_type;
unsigned char *opcode;
int old_fr_fix;
int size = 2;
if (fragP->fr_subtype == EXPLICT_LONG_PREFIX)
fragP->fr_subtype = LONG_PREFIX;
if (S_GET_SEGMENT (fragP->fr_symbol) != segment
&& ((!(fragP->fr_subtype) == EXPLICT_LONG_PREFIX)))
fragP->fr_subtype = ABSOLUTE_ADDR_FOR_DATA;
reloc_type =
(fragP->fr_subtype ? fragP->fr_subtype : ABSOLUTE_ADDR_FOR_DATA);
fragP->fr_subtype = reloc_type;
if (reloc_type == SHORT_PREFIX)
size = 0;
old_fr_fix = fragP->fr_fix;
opcode = (unsigned char *) fragP->fr_opcode;
fragP->fr_fix += (size);
fix_new (fragP, old_fr_fix - 2, size + 2,
fragP->fr_symbol, fragP->fr_offset, 0, reloc_type);
frag_wane (fragP);
return fragP->fr_fix - old_fr_fix;
}
if (fragP->fr_subtype == SHORT_PREFIX)
{
fragP->fr_subtype = SHORT_PREFIX;
return 0;
}
if (fragP->fr_subtype == NO_PREFIX || fragP->fr_subtype == LONG_PREFIX)
{
unsigned long instr;
unsigned long call_addr;
long diff;
fragS *f;
diff = diff ^ diff;;
call_addr = call_addr ^ call_addr;
instr = 0;
f = NULL;
instr = fragP->fr_address + fragP->fr_fix - 2;
call_addr = S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset;
diff = (call_addr - instr) - 1;
if (diff >= (-128 * 2) && diff <= (2 * 127))
{
fragP->fr_subtype = NO_PREFIX;
return 0;
}
fragP->fr_subtype = LONG_PREFIX;
return 2;
}
as_fatal (_("Illegal Reloc type in md_estimate_size_before_relax for line : %d"),
frag_now->fr_line);
return 0;
}
#define MAX_LITTLENUMS 6
char *
md_atof (int type, char * litP, int * sizeP)
{
int prec;
LITTLENUM_TYPE words[4];
char *t;
int i;
switch (type)
{
case 'f':
prec = 2;
break;
case 'd':
prec = 2;
break;
default:
*sizeP = 0;
return _("bad call to md_atof");
}
t = atof_ieee (input_line_pointer, type, words);
if (t)
input_line_pointer = t;
*sizeP = prec * 2;
for (i = prec - 1; i >= 0; i--)
{
md_number_to_chars (litP, (valueT) words[i], 2);
litP += 2;
}
return NULL;
}
void
maxq20_cons_fix_new (fragS * frag, unsigned int off, unsigned int len,
expressionS * exp)
{
int r = 0;
switch (len)
{
case 2:
r = MAXQ_WORDDATA;
break;
case 4:
r = MAXQ_LONGDATA;
break;
}
fix_new_exp (frag, off, len, exp, 0, r);
return;
}
short
tc_coff_fix2rtype (fixS * fixP)
{
return fixP->fx_r_type;
}
int
tc_coff_sizemachdep (fragS *fragP)
{
if (fragP->fr_next)
return (fragP->fr_next->fr_address - fragP->fr_address);
return 0;
}
#ifdef BFD_ASSEMBLER
void
md_convert_frag (bfd * headers ATTRIBUTE_UNUSED,
segT seg ATTRIBUTE_UNUSED,
fragS * fragP)
#else
void
md_convert_frag (object_headers * headers ATTRIBUTE_UNUSED,
segT sec ATTRIBUTE_UNUSED,
fragS * fragP)
#endif
{
char *opcode;
offsetT target_address;
offsetT opcode_address;
offsetT displacement_from_opcode_start;
int address;
opcode = fragP->fr_opcode;
address = 0;
target_address = opcode_address = displacement_from_opcode_start = 0;
target_address =
(S_GET_VALUE (fragP->fr_symbol) / MAXQ_OCTETS_PER_BYTE) +
(fragP->fr_offset / MAXQ_OCTETS_PER_BYTE);
opcode_address =
(fragP->fr_address / MAXQ_OCTETS_PER_BYTE) +
((fragP->fr_fix - 2) / MAXQ_OCTETS_PER_BYTE);
displacement_from_opcode_start = ((target_address - opcode_address) - 1);
if ((displacement_from_opcode_start >= -128
&& displacement_from_opcode_start <= 127)
&& (fragP->fr_subtype == SHORT_PREFIX
|| fragP->fr_subtype == NO_PREFIX))
{
*opcode = (char) displacement_from_opcode_start;
}
else
{
if (fragP->fr_subtype == SHORT_PREFIX)
{
as_bad (_("Cant make long jump/call into short jump/call : %d"),
fragP->fr_line);
return;
}
if (fragP->fr_subtype != SHORT_PREFIX)
{
RELOC_ENUM reloc_type;
int old_fr_fix;
int size = 2;
if (fragP->fr_subtype == NO_PREFIX)
fragP->fr_subtype = LONG_PREFIX;
reloc_type =
(fragP->fr_subtype ? fragP->fr_subtype : LONG_PREFIX);
if (reloc_type == 1)
size = 0;
old_fr_fix = fragP->fr_fix;
fragP->fr_fix += (size);
fix_new (fragP, old_fr_fix - 2, size + 2,
fragP->fr_symbol, fragP->fr_offset, 0, reloc_type);
frag_wane (fragP);
}
}
}
long
md_pcrel_from (fixS *fixP)
{
return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
}
void
maxq_number_to_chars (char *buf, valueT val, int n)
{
if (target_big_endian)
number_to_chars_bigendian (buf, val, n);
else
number_to_chars_littleendian (buf, val, n);
}
void
md_apply_fix3 (fixS *fixP, valueT *valT, segT seg ATTRIBUTE_UNUSED)
{
char *p = fixP->fx_frag->fr_literal + fixP->fx_where;
char *frag_to_fix_at =
fixP->fx_frag->fr_literal + fixP->fx_frag->fr_fix - 2;
if (fixP)
{
if (fixP->fx_frag && valT)
{
if (!fixP->fx_frag->fr_subtype)
fixP->fx_frag->fr_subtype = fixP->fx_r_type;
if ((fixP->fx_frag->fr_subtype == ABSOLUTE_ADDR_FOR_DATA)
|| (fixP->fx_frag->fr_subtype == LONG_PREFIX))
{
*(frag_to_fix_at + 1) = *(p + 1);
maxq_number_to_chars (p + 1, PFX0, 1);
}
#ifdef BFD_ASSEMBLER
fixP->fx_addnumber = *valT;
#endif
}
#ifndef BFD_ASSEMBLER
if (fixP->fx_addsy && S_GET_SEGMENT (fixP->fx_addsy))
segment_info[S_GET_SEGMENT (fixP->fx_addsy)].dot = NULL;
#endif
if (fixP->fx_addsy == NULL)
{
maxq_number_to_chars (p, *valT, fixP->fx_size);
fixP->fx_addnumber = *valT;
fixP->fx_done = 1;
}
}
}
static char mnemonic_chars[256];
static char register_chars[256];
static char operand_chars[256];
static char identifier_chars[256];
static char digit_chars[256];
#define is_mnemonic_char(x) (mnemonic_chars[(unsigned char)(x)])
#define is_register_char(x) (register_chars[(unsigned char)(x)])
#define is_operand_char(x) (operand_chars[(unsigned char)(x)])
#define is_space_char(x) (x==' ')
#define is_identifier_char(x) (identifier_chars[(unsigned char)(x)])
#define is_digit_char(x) (identifier_chars[(unsigned char)(x)])
static char operand_special_chars[] = "[]@.-+";
static char save_stack[32];
static char *save_stack_p;
#define END_STRING_AND_SAVE(s) \
do \
{ \
*save_stack_p++ = *(s); \
*s = '\0'; \
} \
while (0)
#define RESTORE_END_STRING(s) \
do \
{ \
*(s) = *(--save_stack_p); \
} \
while (0)
static maxq20_insn i;
static MAXQ20_OPCODES *current_templates;
static expressionS disp_expressions;
static int this_operand;
static char PFX_INSN[2];
static char INSERT_BUFFER[2];
extern char *input_line_pointer;
static struct hash_control *op_hash;
static struct hash_control *reg_hash;
static struct hash_control *mem_hash;
static struct hash_control *bit_hash;
static struct hash_control *mem_syntax_hash;
const pseudo_typeS md_pseudo_table[] =
{
{"int", cons, 2},
{"maxq10", maxq_target, bfd_mach_maxq10},
{"maxq20", maxq_target, bfd_mach_maxq20},
{NULL, 0, 0},
};
#if defined(BFD_HEADERS)
#ifdef RELSZ
const int md_reloc_size = RELSZ;
#else
const int md_reloc_size = 12;
#endif
#else
const int md_reloc_size = 12;
#endif
#define SET_PFX_ARG(x) (PFX_INSN[1] = x)
static void
set_prefix (void)
{
short int src_index = 0, dst_index = 0;
if (i.operands == 0)
return;
if (i.operands == 1)
{
if (i.types[0] == REG)
{
if (!strcmp (i.op.name, "POP") || !strcmp (i.op.name, "POPI"))
{
dst_index = i.maxq20_op[0].reg[0].Mod_index;
src_index = 0x00;
}
else
{
src_index = i.maxq20_op[0].reg[0].Mod_index;
dst_index = 0x00;
}
}
}
if (i.operands == 2)
{
if (i.types[0] == REG && i.types[1] == REG)
{
dst_index = i.maxq20_op[0].reg[0].Mod_index;
src_index = i.maxq20_op[1].reg[0].Mod_index;
}
else if (i.types[0] != REG && i.types[1] == REG)
{
src_index = i.maxq20_op[1].reg[0].Mod_index;
dst_index = 0x00;
}
else if (i.types[0] == REG && i.types[1] != REG)
{
dst_index = i.maxq20_op[0].reg[0].Mod_index;
src_index = 0x00;
}
else if (i.types[0] == BIT && i.maxq20_op[0].r_bit)
{
dst_index = i.maxq20_op[0].r_bit->reg->Mod_index;
src_index = 0x00;
}
else if (i.types[1] == BIT && i.maxq20_op[1].r_bit)
{
dst_index = 0x00;
src_index = i.maxq20_op[1].r_bit->reg->Mod_index;
}
}
if (src_index >= 0x00 && src_index <= 0xF)
{
if (dst_index >= 0x00 && dst_index <= 0x07)
i.prefix = 0;
else if (dst_index >= 0x08 && dst_index <= 0x0F)
i.prefix = 2;
else if (dst_index >= 0x10 && dst_index <= 0x17)
i.prefix = 4;
else if (dst_index >= 0x18 && dst_index <= 0x1F)
i.prefix = 6;
}
else if (src_index >= 0x10 && src_index <= 0x1F)
{
if (dst_index >= 0x00 && dst_index <= 0x07)
i.prefix = 1;
else if (dst_index >= 0x08 && dst_index <= 0x0F)
i.prefix = 3;
else if (dst_index >= 0x10 && dst_index <= 0x17)
i.prefix = 5;
else if (dst_index >= 0x18 && dst_index <= 0x1F)
i.prefix = 7;
}
}
static unsigned char
is_a_LSinstr (const char *ln_pointer)
{
int i = 0;
for (i = 0; LSInstr[i] != NULL; i++)
if (!strcmp (LSInstr[i], ln_pointer))
return 1;
return 0;
}
static void
LS_processing (const char *line)
{
if (is_a_LSinstr (line))
{
if ((line[0] == 'L') || (line[0] == 'l'))
{
i.prefix = 0;
INSERT_BUFFER[0] = PFX0;
i.Instr_Prefix = LONG_PREFIX;
}
else if ((line[0] == 'S') || (line[0] == 's'))
i.Instr_Prefix = SHORT_PREFIX;
else
i.Instr_Prefix = NO_PREFIX;
}
else
i.Instr_Prefix = LONG_PREFIX;
}
static char *
parse_insn (char *line, char *mnemonic)
{
char *l = line;
char *token_start = l;
char *mnem_p;
char temp[MAX_MNEM_SIZE];
int ii = 0;
memset (temp, END_OF_INSN, MAX_MNEM_SIZE);
mnem_p = mnemonic;
while ((*mnem_p = mnemonic_chars[(unsigned char) *l]) != 0)
{
ii++;
mnem_p++;
if (mnem_p >= mnemonic + MAX_MNEM_SIZE)
{
as_bad (_("no such instruction: `%s'"), token_start);
return NULL;
}
l++;
}
if (!is_space_char (*l) && *l != END_OF_INSN)
{
as_bad (_("invalid character %s in mnemonic"), l);
return NULL;
}
while (ii)
{
temp[ii - 1] = toupper ((char) mnemonic[ii - 1]);
ii--;
}
LS_processing (temp);
if (i.Instr_Prefix != 0 && is_a_LSinstr (temp))
memcpy (temp, temp + 1, MAX_MNEM_SIZE);
current_templates = (MAXQ20_OPCODES *) hash_find (op_hash, temp);
if (current_templates != NULL)
return l;
as_bad (_("no such instruction: `%s'"), token_start);
return NULL;
}
static int
pwr (int x, int y)
{
int k, ans = 1;
for (k = 0; k < y; k++)
ans *= x;
return ans;
}
static reg_entry *
parse_reg_by_index (char *imm_start)
{
int k = 0, mid = 0, rid = 0, val = 0, j = 0;
char temp[4] = { 0 };
reg_entry *reg = NULL;
do
{
if (isdigit (imm_start[k]))
temp[k] = imm_start[k] - '0';
else if (isalpha (imm_start[k])
&& (imm_start[k] = tolower (imm_start[k])) < 'g')
temp[k] = 10 + (int) (imm_start[k] - 'a');
else if (imm_start[k] == 'h')
break;
else if (imm_start[k] == END_OF_INSN)
{
imm_start[k] = 'd';
break;
}
else
return NULL;
k++;
}
while (imm_start[k] != '\n');
switch (imm_start[k])
{
case 'h':
for (j = 0; j < k; j++)
val += temp[j] * pwr (16, k - j - 1);
break;
case 'd':
for (j = 0; j < k; j++)
{
if (temp[j] > 9)
return NULL;
val += temp[j] * pwr (10, k - j - 1);
break;
}
}
mid = val & 0x0f;
rid = (val >> 4) & 0x0f;
if (mid < 6)
{
for (j = 0; j < num_of_reg; j++)
{
if (new_reg_table[j].opcode == val)
{
reg = (reg_entry *) & new_reg_table[j];
break;
}
}
}
else
{
j = 0;
while (system_reg_table[j].reg_name != NULL)
{
if (system_reg_table[j].opcode == val)
{
reg = (reg_entry *) & system_reg_table[j];
break;
}
j++;
}
}
if (reg == NULL)
{
as_bad (_("Invalid register value %s"), imm_start);
return reg;
}
#if CHANGE_PFX
if (this_operand == 0 && reg != NULL)
{
if (reg->Mod_index > 7)
i.prefix = 2;
else
i.prefix = 0;
}
#endif
return (reg_entry *) reg;
}
static reg_entry *
parse_register (char *reg_string, char **end_op)
{
char *s = reg_string;
char *p = NULL;
char reg_name_given[MAX_REG_NAME_SIZE + 1];
reg_entry *r = NULL;
r = NULL;
p = NULL;
if (is_space_char (*s))
++s;
p = reg_name_given;
while ((*p++ = register_chars[(unsigned char) *s]) != '\0')
{
if (p >= reg_name_given + MAX_REG_NAME_SIZE)
return (reg_entry *) NULL;
s++;
}
*end_op = s;
r = (reg_entry *) hash_find (reg_hash, reg_name_given);
#if CHANGE_PFX
if (this_operand == 0 && r != NULL)
{
if (r->Mod_index > 7)
i.prefix = 2;
else
i.prefix = 0;
}
#endif
return r;
}
static reg_bit *
parse_register_bit (char *reg_string, char **end_op)
{
const char *s = reg_string;
short k = 0;
char diff = 0;
reg_bit *rb = NULL;
reg_entry *r = NULL;
bit_name *b = NULL;
char temp_bitname[MAX_REG_NAME_SIZE + 2];
char temp[MAX_REG_NAME_SIZE + 1];
memset (&temp, '\0', (MAX_REG_NAME_SIZE + 1));
memset (&temp_bitname, '\0', (MAX_REG_NAME_SIZE + 2));
diff = 0;
r = NULL;
rb = NULL;
rb = xmalloc (sizeof (reg_bit));
rb->reg = xmalloc (sizeof (reg_entry));
k = 0;
b = (bit_name *) hash_find (bit_hash, reg_string);
if (b != NULL)
{
*end_op = reg_string + strlen (reg_string);
strcpy (temp_bitname, b->reg_bit);
s = temp_bitname;
}
if (strchr (s, '.'))
{
while (*s != '.')
{
if (*s == '\0')
return NULL;
temp[k] = *s++;
k++;
}
temp[k] = '\0';
}
if ((r = parse_register (temp, end_op)) == NULL)
return NULL;
rb->reg = r;
s++;
if (isdigit ((char) *s))
rb->bit = atoi (s);
else if (isalpha ((char) *s))
{
rb->bit = (char) *s - 'a';
rb->bit += 10;
if (rb->bit > 15)
{
as_bad (_("Invalid bit number : '%c'"), (char) *s);
return NULL;
}
}
if (b != NULL)
diff = strlen (temp_bitname) - strlen (temp) - 1;
else
diff = strlen (reg_string) - strlen (temp) - 1;
if (*(s + diff) != '\0')
{
as_bad (_("Illegal character after operand '%s'"), reg_string);
return NULL;
}
return rb;
}
static void
pfx_for_imm_val (int arg)
{
if (i.prefix == -1)
return;
if (i.prefix == 0 && arg == 0 && PFX_INSN[1] == 0 && !(i.data_operands))
return;
if (!(i.prefix < 0) && !(i.prefix > 7))
PFX_INSN[0] = (i.prefix << 4) | PFX0;
if (!PFX_INSN[1])
PFX_INSN[1] = arg;
}
static int
maxq20_immediate (char *imm_start)
{
int val = 0, val_pfx = 0;
char sign_val = 0;
int k = 0, j;
int temp[4] = { 0 };
imm_start++;
if (imm_start[1] == '\0' && (imm_start[0] == '0' || imm_start[0] == '1')
&& (this_operand == 1 && ((i.types[0] == BIT || i.types[0] == FLAG))))
{
val = imm_start[0] - '0';
i.imm_bit_operands++;
i.types[this_operand] = IMMBIT;
i.maxq20_op[this_operand].imms = (char) val;
#if CHANGE_PFX
if (i.prefix == 2)
pfx_for_imm_val (0);
#endif
return 1;
}
sign_val = 0;
do
{
if (imm_start[k] == '-' && k == 0)
sign_val = -1;
else if (imm_start[k] == '+' && k == 0)
sign_val = 1;
else if (isdigit (imm_start[k]))
temp[k] = imm_start[k] - '0';
else if (isalpha (imm_start[k])
&& (imm_start[k] = tolower (imm_start[k])) < 'g')
temp[k] = 10 + (int) (imm_start[k] - 'a');
else if (imm_start[k] == 'h')
break;
else if (imm_start[k] == '\0')
{
imm_start[k] = 'd';
break;
}
else
{
as_bad (_("Invalid Character in immediate Value : %c"),
imm_start[k]);
return 0;
}
k++;
}
while (imm_start[k] != '\n');
switch (imm_start[k])
{
case 'h':
for (j = (sign_val ? 1 : 0); j < k; j++)
val += temp[j] * pwr (16, k - j - 1);
break;
case 'd':
for (j = (sign_val ? 1 : 0); j < k; j++)
{
if (temp[j] > 9)
{
as_bad (_("Invalid Character in immediate value : %c"),
imm_start[j]);
return 0;
}
val += temp[j] * pwr (10, k - j - 1);
}
}
if (!sign_val)
sign_val = 1;
if (val > 65535)
{
as_bad (_("Immediate value greater than 16 bits"));
return 0;
}
val = val * sign_val;
if (this_operand == 1)
{
if ((val * sign_val) > MAX_STACK && i.types[0] == REG
&& !strcmp (i.maxq20_op[0].reg->reg_name, "SP"))
{
as_warn (_
("Attempt to move a value in the stack pointer greater than the size of the stack"));
val = val & MAX_STACK;
}
else if (((val * sign_val) > 0xFF) && (i.types[0] == REG)
&& (i.maxq20_op[0].reg->rtype == Reg_8W))
{
as_warn (_
("Attempt to move 16 bit value into an 8 bit register.Truncating..\n"));
val = val & 0xfe;
}
else if (((sign_val == -1) || (val > 0xFF)) && (i.types[0] == REG)
&& (i.maxq20_op[0].reg->rtype == Reg_8W))
{
val_pfx = val >> 8;
val = ((val) & 0x00ff);
SET_PFX_ARG (val_pfx);
i.maxq20_op[this_operand].imms = (char) val;
}
else if ((val <= 0xff) && (i.types[0] == REG)
&& (i.maxq20_op[0].reg->rtype == Reg_8W))
i.maxq20_op[this_operand].imms = (char) val;
else if (((sign_val == -1) || val > 0xFE) && i.types[0] == REG
&& i.maxq20_op[0].reg->rtype == Reg_16W)
{
val_pfx = val >> 8;
val = ((val) & 0x00ff);
SET_PFX_ARG (val_pfx);
i.maxq20_op[this_operand].imms = (char) val;
}
else if (val < 0xFF && i.types[0] == REG
&& i.maxq20_op[0].reg->rtype == Reg_16W)
{
i.maxq20_op[this_operand].imms = (char) val;
}
else if (i.types[0] == MEM)
{
if ((sign_val == -1) || val > 0xFE)
{
val_pfx = val >> 8;
val = ((val) & 0x00ff);
SET_PFX_ARG (val_pfx);
i.maxq20_op[this_operand].imms = (char) val;
}
else
i.maxq20_op[this_operand].imms = (char) val;
}
else if (val < 0xFF && i.types[0] == FLAG)
i.maxq20_op[this_operand].imms = (char) val;
else if ((((sign_val == -1) || val > 0xFE)) && i.types[0] == FLAG)
{
val_pfx = val >> 8;
val = ((val) & 0x00ff);
SET_PFX_ARG (val_pfx);
i.maxq20_op[this_operand].imms = (char) val;
}
else
{
as_bad (_("Invalid immediate move operation"));
return 0;
}
}
else
{
if ((sign_val == -1) || val > 0xFE)
{
val_pfx = val >> 8;
val = ((val) & 0x00ff);
SET_PFX_ARG (val_pfx);
i.maxq20_op[this_operand].imms = (char) val;
}
else
i.maxq20_op[this_operand].imms = (char) val;
}
i.imm_operands++;
return 1;
}
static int
extract_int_val (const char *imm_start)
{
int k, j, val;
char sign_val;
int temp[4];
k = 0;
j = 0;
val = 0;
sign_val = 0;
do
{
if (imm_start[k] == '-' && k == 0)
sign_val = -1;
else if (imm_start[k] == '+' && k == 0)
sign_val = 1;
else if (isdigit (imm_start[k]))
temp[k] = imm_start[k] - '0';
else if (isalpha (imm_start[k]) && (tolower (imm_start[k])) < 'g')
temp[k] = 10 + (int) (tolower (imm_start[k]) - 'a');
else if (tolower (imm_start[k]) == 'h')
break;
else if ((imm_start[k] == '\0') || (imm_start[k] == ']'))
break;
else
{
as_bad (_("Invalid Character in immediate Value : %c"),
imm_start[k]);
return 0;
}
k++;
}
while (imm_start[k] != '\n');
switch (imm_start[k])
{
case 'h':
for (j = (sign_val ? 1 : 0); j < k; j++)
val += temp[j] * pwr (16, k - j - 1);
break;
default:
for (j = (sign_val ? 1 : 0); j < k; j++)
{
if (temp[j] > 9)
{
as_bad (_("Invalid Character in immediate value : %c"),
imm_start[j]);
return 0;
}
val += temp[j] * pwr (10, k - j - 1);
}
}
if (!sign_val)
sign_val = 1;
return val * sign_val;
}
static char
check_for_parse (const char *line)
{
int val;
if (*(line + 1) == '[')
{
do
{
line++;
if ((*line == '-') || (*line == '+'))
break;
}
while (!is_space_char (*line));
if ((*line == '-') || (*line == '+'))
val = extract_int_val (line);
else
val = extract_int_val (line + 1);
INSERT_BUFFER[0] = 0x3E;
INSERT_BUFFER[1] = val;
return 1;
}
return 0;
}
static mem_access *
maxq20_mem_access (char *mem_string, char **end_op)
{
char *s = mem_string;
char *p;
char mem_name_given[MAX_MEM_NAME_SIZE + 1];
mem_access *m;
m = NULL;
if (is_space_char (*s))
++s;
p = mem_name_given;
while ((*p++ = register_chars[(unsigned char) *s]) != '\0')
{
if (p >= mem_name_given + MAX_MEM_NAME_SIZE)
return (mem_access *) NULL;
s++;
}
*end_op = s;
m = (mem_access *) hash_find (mem_hash, mem_name_given);
return m;
}
static symbolS *
maxq20_data (char *op_string)
{
symbolS *symbolP;
symbolP = symbol_find (op_string);
if (symbolP != NULL
&& S_GET_SEGMENT (symbolP) != now_seg
&& S_GET_SEGMENT (symbolP) !=
#ifdef BFD_ASSEMBLER
bfd_und_section_ptr
#else
SEG_UNKNOWN
#endif
)
{
int val_pfx;
#ifdef BFD_ASSEMBLER
val_pfx = 0;
#else
val_pfx = (symbolP->sy_value.X_add_number) >> 8;
#endif
pfx_for_imm_val (val_pfx);
return symbolP;
}
return NULL;
}
static int
maxq20_displacement (char *disp_start, char *disp_end)
{
expressionS *exp;
segT exp_seg = 0;
char *save_input_line_pointer;
#ifndef LEX_AT
char *gotfree_input_line;
#endif
gotfree_input_line = NULL;
exp = &disp_expressions;
i.maxq20_op[this_operand].disps = exp;
i.disp_operands++;
save_input_line_pointer = input_line_pointer;
input_line_pointer = disp_start;
END_STRING_AND_SAVE (disp_end);
#ifndef LEX_AT
#endif
exp_seg = expression (exp);
SKIP_WHITESPACE ();
if (*input_line_pointer)
as_bad (_("junk `%s' after expression"), input_line_pointer);
#if GCC_ASM_O_HACK
RESTORE_END_STRING (disp_end + 1);
#endif
RESTORE_END_STRING (disp_end);
input_line_pointer = save_input_line_pointer;
#ifndef LEX_AT
if (gotfree_input_line)
free (gotfree_input_line);
#endif
if (exp->X_op == O_absent || exp->X_op == O_big)
{
as_bad (_("missing or invalid displacement expression `%s' taken as 0"),
disp_start);
exp->X_op = O_constant;
exp->X_add_number = 0;
exp->X_add_symbol = (symbolS *) 0;
exp->X_op_symbol = (symbolS *) 0;
}
#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
if (exp->X_op != O_constant
#ifdef BFD_ASSEMBLER
&& OUTPUT_FLAVOR == bfd_target_aout_flavour
#endif
&& exp_seg != absolute_section
&& exp_seg != text_section
&& exp_seg != data_section
&& exp_seg != bss_section && exp_seg != undefined_section
#ifdef BFD_ASSEMBLER
&& !bfd_is_com_section (exp_seg)
#endif
)
{
#ifdef BFD_ASSEMBLER
as_bad (_("unimplemented segment %s in operand"), exp_seg->name);
#else
as_bad (_("unimplemented segment type %d in operand"), exp_seg);
#endif
return 0;
}
#endif
i.maxq20_op[this_operand].disps = exp;
return 1;
}
static int
maxq20_operand (char *operand_string)
{
reg_entry *r = NULL;
reg_bit *rb = NULL;
mem_access *m = NULL;
char *end_op = NULL;
symbolS *sym = NULL;
char *base_string = NULL;
int ii = 0;
char *displacement_string_start = NULL;
char *displacement_string_end = NULL;
char case_str_op_string[MAX_OPERAND_SIZE + 1];
char str_op_string[MAX_OPERAND_SIZE + 1];
char *org_case_op_string = case_str_op_string;
char *op_string = str_op_string;
memset (op_string, END_OF_INSN, (MAX_OPERAND_SIZE + 1));
memset (org_case_op_string, END_OF_INSN, (MAX_OPERAND_SIZE + 1));
memcpy (op_string, operand_string, strlen (operand_string) + 1);
memcpy (org_case_op_string, operand_string, strlen (operand_string) + 1);
ii = strlen (operand_string) + 1;
if (ii > MAX_OPERAND_SIZE)
{
as_bad (_("Size of Operand '%s' greater than %d"), op_string,
MAX_OPERAND_SIZE);
return 0;
}
while (ii)
{
op_string[ii - 1] = toupper ((char) op_string[ii - 1]);
ii--;
}
if (is_space_char (*op_string))
++op_string;
if (isxdigit (operand_string[0]))
{
r = parse_reg_by_index (op_string);
if (r != NULL)
{
if (is_space_char (*op_string))
++op_string;
i.types[this_operand] = REG;
i.maxq20_op[this_operand].reg = r;
i.reg_operands++;
return 1;
}
memcpy (op_string, operand_string, strlen (operand_string) + 1);
ii = strlen (operand_string) + 1;
while (ii)
{
op_string[ii - 1] = toupper ((char) op_string[ii - 1]);
ii--;
}
}
if (!strcmp (op_string, "Z"))
{
if (is_space_char (*op_string))
++op_string;
i.types[this_operand] = FLAG;
i.maxq20_op[this_operand].flag = FLAG_Z;
i.flag_operands++;
return 1;
}
else if (!strcmp (op_string, "NZ"))
{
if (is_space_char (*op_string))
++op_string;
i.types[this_operand] = FLAG;
i.maxq20_op[this_operand].flag = FLAG_NZ;
i.flag_operands++;
return 1;
}
else if (!strcmp (op_string, "NC"))
{
if (is_space_char (*op_string))
++op_string;
i.types[this_operand] = FLAG;
i.maxq20_op[this_operand].flag = FLAG_NC;
i.flag_operands++;
return 1;
}
else if (!strcmp (op_string, "E"))
{
if (is_space_char (*op_string))
++op_string;
i.types[this_operand] = FLAG;
i.maxq20_op[this_operand].flag = FLAG_E;
i.flag_operands++;
return 1;
}
else if (!strcmp (op_string, "S"))
{
if (is_space_char (*op_string))
++op_string;
i.types[this_operand] = FLAG;
i.maxq20_op[this_operand].flag = FLAG_S;
i.flag_operands++;
return 1;
}
else if (!strcmp (op_string, "C"))
{
if (is_space_char (*op_string))
++op_string;
i.types[this_operand] = FLAG;
i.maxq20_op[this_operand].flag = FLAG_C;
i.flag_operands++;
return 1;
}
else if (!strcmp (op_string, "NE"))
{
if (is_space_char (*op_string))
++op_string;
i.types[this_operand] = FLAG;
i.maxq20_op[this_operand].flag = FLAG_NE;
i.flag_operands++;
return 1;
}
else if ((rb = parse_register_bit (op_string, &end_op)) != NULL)
{
op_string = end_op;
if (is_space_char (*op_string))
++op_string;
i.types[this_operand] = BIT;
i.maxq20_op[this_operand].r_bit = rb;
i.bit_operands++;
return 1;
}
else if (*op_string == IMMEDIATE_PREFIX)
{
if (is_space_char (*op_string))
++op_string;
i.types[this_operand] = IMM;
if (!maxq20_immediate (op_string))
{
as_bad (_("illegal immediate operand '%s'"), op_string);
return 0;
}
return 1;
}
else if (*op_string == ABSOLUTE_PREFIX || !strcmp (op_string, "NUL"))
{
if (is_space_char (*op_string))
++op_string;
if (check_for_parse (op_string))
{
memset (op_string, '\0', strlen (op_string) + 1);
memcpy (op_string, "@BP[OFFS]\0", 11);
}
i.types[this_operand] = MEM;
if ((m = maxq20_mem_access (op_string, &end_op)) == NULL)
{
as_bad (_("Invalid operand for memory access '%s'"), op_string);
return 0;
}
i.maxq20_op[this_operand].mem = m;
i.mem_operands++;
return 1;
}
else if ((r = parse_register (op_string, &end_op)) != NULL)
{
op_string = end_op;
if (is_space_char (*op_string))
++op_string;
i.types[this_operand] = REG;
i.maxq20_op[this_operand].reg = r;
i.reg_operands++;
return 1;
}
if (this_operand == 1)
{
if ((sym = maxq20_data (org_case_op_string)) != NULL)
{
while (is_space_char (*op_string))
++op_string;
i.types[this_operand] = DATA;
i.maxq20_op[this_operand].data = sym;
i.data_operands++;
return 1;
}
else if (is_digit_char (*op_string) || is_identifier_char (*op_string))
{
base_string = org_case_op_string + strlen (org_case_op_string);
--base_string;
if (is_space_char (*base_string))
--base_string;
displacement_string_start = org_case_op_string;
displacement_string_end = base_string + 1;
if (displacement_string_start != displacement_string_end)
{
if (!maxq20_displacement (displacement_string_start,
displacement_string_end))
{
as_bad (_("illegal displacement operand "));
return 0;
}
i.types[this_operand] = DISP;
return 1;
}
}
}
else if (is_digit_char (*op_string) || is_identifier_char (*op_string))
{
base_string = org_case_op_string + strlen (org_case_op_string);
--base_string;
if (is_space_char (*base_string))
--base_string;
displacement_string_start = org_case_op_string;
displacement_string_end = base_string + 1;
if (displacement_string_start != displacement_string_end)
{
if (!maxq20_displacement (displacement_string_start,
displacement_string_end))
return 0;
i.types[this_operand] = DISP;
}
}
return 1;
}
static char *
parse_operands (char *l, const char *mnemonic)
{
char *token_start;
short int expecting_operand = 0;
short int paren_not_balanced;
int operand_ok;
if (mnemonic)
operand_ok = 0;
while (*l != END_OF_INSN)
{
if (is_space_char (*l))
++l;
if (!is_operand_char (*l) && *l != END_OF_INSN)
{
as_bad (_("invalid character %c before operand %d"),
(char) (*l), i.operands + 1);
return NULL;
}
token_start = l;
paren_not_balanced = 0;
while (paren_not_balanced || *l != ',')
{
if (*l == END_OF_INSN)
{
if (paren_not_balanced)
{
as_bad (_("unbalanced brackets in operand %d."),
i.operands + 1);
return NULL;
}
break;
}
else if (!is_operand_char (*l) && !is_space_char (*l))
{
as_bad (_("invalid character %c in operand %d"),
(char) (*l), i.operands + 1);
return NULL;
}
if (*l == '[')
++paren_not_balanced;
if (*l == ']')
--paren_not_balanced;
l++;
}
if (l != token_start)
{
this_operand = i.operands++;
if (i.operands > MAX_OPERANDS)
{
as_bad (_("spurious operands; (%d operands/instruction max)"),
MAX_OPERANDS);
return NULL;
}
END_STRING_AND_SAVE (l);
operand_ok = maxq20_operand (token_start);
RESTORE_END_STRING (l);
if (!operand_ok)
return NULL;
}
else
{
if (expecting_operand)
{
expecting_operand_after_comma:
as_bad (_("expecting operand after ','; got nothing"));
return NULL;
}
}
if (*l == ',')
{
if (*(++l) == END_OF_INSN)
goto expecting_operand_after_comma;
expecting_operand = 1;
}
}
return l;
}
static int
match_operands (int type, MAX_ARG_TYPE flag_type, MAX_ARG_TYPE arg_type,
int op_num)
{
switch (type)
{
case REG:
if ((arg_type & A_REG) == A_REG)
return 1;
break;
case IMM:
if ((arg_type & A_IMM) == A_IMM)
return 1;
break;
case IMMBIT:
if ((arg_type & A_BIT_0) == A_BIT_0 && (i.maxq20_op[op_num].imms == 0))
return 1;
else if ((arg_type & A_BIT_1) == A_BIT_1
&& (i.maxq20_op[op_num].imms == 1))
return 1;
break;
case MEM:
if ((arg_type & A_MEM) == A_MEM)
return 1;
break;
case FLAG:
if ((arg_type & flag_type) == flag_type)
return 1;
break;
case BIT:
if ((arg_type & ACC_BIT) == ACC_BIT && !strcmp (i.maxq20_op[op_num].r_bit->reg->reg_name, "ACC"))
return 1;
else if ((arg_type & SRC_BIT) == SRC_BIT && (op_num == 1))
return 1;
else if ((op_num == 0) && (arg_type & DST_BIT) == DST_BIT)
return 1;
break;
case DISP:
if ((arg_type & A_DISP) == A_DISP)
return 1;
case DATA:
if ((arg_type & A_DATA) == A_DATA)
return 1;
case BIT_BUCKET:
if ((arg_type & A_BIT_BUCKET) == A_BIT_BUCKET)
return 1;
}
return 0;
}
static int
match_template (void)
{
const MAXQ20_OPCODE_INFO *t;
char inv_oper;
inv_oper = 0;
for (t = current_templates->start; t < current_templates->end; t++)
{
if (i.operands != t->op_number)
continue;
else if (!t->op_number)
break;
switch (i.operands)
{
case 2:
if (!match_operands (i.types[1], i.maxq20_op[1].flag, t->arg[1], 1))
{
inv_oper = 1;
continue;
}
case 1:
if (!match_operands (i.types[0], i.maxq20_op[0].flag, t->arg[0], 0))
{
inv_oper = 2;
continue;
}
}
break;
}
if (t == current_templates->end)
{
as_bad (_("operand %d is invalid for `%s'"),
inv_oper, current_templates->start->name);
return 0;
}
i.op = *t;
return 1;
}
static int
match_filters (void)
{
if (!strcmp (i.op.name, "AND") || !strcmp (i.op.name, "OR")
|| !strcmp (i.op.name, "XOR") || !strcmp (i.op.name, "ADD")
|| !strcmp (i.op.name, "ADDC") || !strcmp (i.op.name, "SUB")
|| !strcmp (i.op.name, "SUBB"))
{
if (i.types[0] == REG)
{
if (i.maxq20_op[0].reg->Mod_name == 0xa)
{
as_bad (_
("The Accumulator cannot be used as a source in ALU instructions\n"));
return 0;
}
}
}
if (!strcmp (i.op.name, "MOVE") && (i.types[0] == MEM || i.types[1] == MEM)
&& i.operands == 2)
{
mem_access_syntax *mem_op = NULL;
if (i.types[0] == MEM)
{
mem_op =
(mem_access_syntax *) hash_find (mem_syntax_hash,
i.maxq20_op[0].mem->name);
if ((mem_op->type == SRC) && mem_op)
{
as_bad (_("'%s' operand cant be used as destination in %s"),
mem_op->name, i.op.name);
return 0;
}
else if ((mem_op->invalid_op != NULL) && (i.types[1] == MEM)
&& mem_op)
{
int k = 0;
for (k = 0; k < 5 || !mem_op->invalid_op[k]; k++)
{
if (mem_op->invalid_op[k] != NULL)
if (!strcmp
(mem_op->invalid_op[k], i.maxq20_op[1].mem->name))
{
as_bad (_
("Invalid Instruction '%s' operand cant be used with %s"),
mem_op->name, i.maxq20_op[1].mem->name);
return 0;
}
}
}
}
if (i.types[1] == MEM)
{
mem_op = NULL;
mem_op =
(mem_access_syntax *) hash_find (mem_syntax_hash,
i.maxq20_op[1].mem->name);
if (mem_op->type == DST && mem_op)
{
as_bad (_("'%s' operand cant be used as source in %s"),
mem_op->name, i.op.name);
return 0;
}
else if (mem_op->invalid_op != NULL && i.types[0] == MEM && mem_op)
{
int k = 0;
for (k = 0; k < 5 || !mem_op->invalid_op[k]; k++)
{
if (mem_op->invalid_op[k] != NULL)
if (!strcmp
(mem_op->invalid_op[k], i.maxq20_op[0].mem->name))
{
as_bad (_
("Invalid Instruction '%s' operand cant be used with %s"),
mem_op->name, i.maxq20_op[0].mem->name);
return 0;
}
}
}
else if (i.types[0] == REG
&& !strcmp (i.maxq20_op[0].reg->reg_name, "OFFS")
&& mem_op)
{
if (!strcmp (mem_op->name, "@BP[OFFS--]")
|| !strcmp (mem_op->name, "@BP[OFFS++]"))
{
as_bad (_
("Invalid Instruction '%s' operand cant be used with %s"),
mem_op->name, i.maxq20_op[0].mem->name);
return 0;
}
}
}
}
if ((i.types[0] == MEM) && (i.operands == 1)
&& !(!strcmp (i.op.name, "POP") || !strcmp (i.op.name, "POPI")))
{
mem_access_syntax *mem_op = NULL;
if (i.types[0] == MEM)
{
mem_op =
(mem_access_syntax *) hash_find (mem_syntax_hash,
i.maxq20_op[0].mem->name);
if (mem_op->type == DST && mem_op)
{
as_bad (_("'%s' operand cant be used as source in %s"),
mem_op->name, i.op.name);
return 0;
}
}
}
if (i.operands == 2 && i.types[0] == IMM)
{
as_bad (_("'%s' instruction cant have first operand as Immediate vale"),
i.op.name);
return 0;
}
if (!strcmp (i.op.name, "PUSH") || !strcmp (i.op.name, "POP")
|| !strcmp (i.op.name, "POPI"))
{
if (i.types[0] == REG)
{
if (!strcmp (i.maxq20_op[0].reg->reg_name, "SP"))
{
as_bad (_("SP cannot be used with %s\n"), i.op.name);
return 0;
}
}
else if (i.types[0] == MEM
&& !strcmp (i.maxq20_op[0].mem->name, "@SP--"))
{
as_bad (_("@SP-- cannot be used with PUSH\n"));
return 0;
}
}
if (!strcmp (i.op.name, "MOVE") && i.mem_operands == 2)
{
if (strlen (i.maxq20_op[0].mem->name) != 6 ||
strcmp (i.maxq20_op[0].mem->name, i.maxq20_op[1].mem->name))
{
if (!strncmp (i.maxq20_op[0].mem->name, "@DP", 3)
&& !strncmp (i.maxq20_op[1].mem->name, "@DP", 3))
{
as_bad (_
("Operands either contradictory or use the data bus in read/write state together"));
return 0;
}
if (!strncmp (i.maxq20_op[0].mem->name, "@SP", 3)
&& !strncmp (i.maxq20_op[1].mem->name, "@SP", 3))
{
as_bad (_
("Operands either contradictory or use the data bus in read/write state together"));
return 0;
}
}
if ((i.maxq20_op[1].mem != NULL)
&& !strncmp (i.maxq20_op[1].mem->name, "NUL", 3))
{
as_bad (_("MOVE Cant Use NUL as SRC"));
return 0;
}
}
if (!strcmp (i.op.name, "MOVE") && i.mem_operands == 1
&& i.reg_operands == 1)
{
int memnum, regnum;
memnum = (i.types[0] == MEM) ? 0 : 1;
regnum = (memnum == 0) ? 1 : 0;
if (!strncmp (i.maxq20_op[regnum].reg->reg_name, "DP", 2) &&
!strncmp ((i.maxq20_op[memnum].mem->name) + 1,
i.maxq20_op[regnum].reg->reg_name, 5)
&& strcmp ((i.maxq20_op[memnum].mem->name) + 1,
i.maxq20_op[regnum].reg->reg_name))
{
as_bad (_
("Contradictory movement between DP register and memory access using DP"));
return 0;
}
else if (!strcmp (i.maxq20_op[regnum].reg->reg_name, "SP") &&
!strncmp ((i.maxq20_op[memnum].mem->name) + 1,
i.maxq20_op[regnum].reg->reg_name, 2))
{
as_bad (_
("SP and @SP-- cannot be used together in a move instruction"));
return 0;
}
}
if (i.bit_operands == 1 && i.operands == 2)
{
int bitnum = (i.types[0] == BIT) ? 0 : 1;
if (strcmp (i.maxq20_op[bitnum].r_bit->reg->reg_name, "ACC"))
{
if (i.maxq20_op[bitnum].r_bit->reg->Mod_name >= 0x7 &&
i.maxq20_op[bitnum].r_bit->reg->Mod_name != CTRL)
{
as_bad (_
("Only Module 8 system registers allowed in this operation"));
return 0;
}
}
}
if (i.bit_operands == 1 || i.operands == 2)
{
int bitnum = 0, size = 0;
bitnum = (i.types[0] == BIT) ? 0 : 1;
if (i.bit_operands == 1)
{
switch (i.maxq20_op[bitnum].r_bit->reg->rtype)
{
case Reg_8W:
size = 7;
break;
case Reg_16W:
size = 15;
break;
case Reg_8R:
size = 7;
if (bitnum == 0)
{
as_fatal (_("Read only Register used as destination"));
return 0;
}
break;
case Reg_16R:
size = 15;
if (bitnum == 0)
{
as_fatal (_("Read only Register used as destination"));
return 0;
}
break;
}
if (size < (i.maxq20_op[bitnum].r_bit)->bit)
{
as_bad (_("Bit No '%d'exceeds register size in this operation"),
(i.maxq20_op[bitnum].r_bit)->bit);
return 0;
}
}
if (i.bit_operands == 2)
{
switch ((i.maxq20_op[0].r_bit)->reg->rtype)
{
case Reg_8W:
size = 7;
break;
case Reg_16W:
size = 15;
break;
case Reg_8R:
case Reg_16R:
as_fatal (_("Read only Register used as destination"));
return 0;
}
if (size < (i.maxq20_op[0].r_bit)->bit)
{
as_bad (_
("Bit No '%d' exceeds register size in this operation"),
(i.maxq20_op[0].r_bit)->bit);
return 0;
}
size = 0;
switch ((i.maxq20_op[1].r_bit)->reg->rtype)
{
case Reg_8R:
case Reg_8W:
size = 7;
break;
case Reg_16R:
case Reg_16W:
size = 15;
break;
}
if (size < (i.maxq20_op[1].r_bit)->bit)
{
as_bad (_
("Bit No '%d' exceeds register size in this operation"),
(i.maxq20_op[1].r_bit)->bit);
return 0;
}
}
}
if (!strcmp (i.op.name, "JUMP") || !strcmp (i.op.name, "CALL")
|| !strncmp (i.op.name, "DJNZ", 4))
{
if (i.mem_operands)
as_warn (_
("Memory References cannot be used with branching operations\n"));
}
if (!strcmp (i.op.name, "DJNZ"))
{
if (!
(strcmp (i.maxq20_op[0].reg->reg_name, "LC[0]")
|| strcmp (i.maxq20_op[0].reg->reg_name, "LC[1]")))
{
as_bad (_("DJNZ uses only LC[n] register \n"));
return 0;
}
}
if ((i.operands == 2 && i.types[0] == REG) || !strcmp (i.op.name, "POP")
|| !strcmp (i.op.name, "POPI"))
{
int regnum = 0;
if (!strcmp (i.op.name, "POP") || !strcmp (i.op.name, "POPI"))
{
regnum = 0;
if (i.types[regnum] == MEM)
{
mem_access_syntax *mem_op = NULL;
mem_op =
(mem_access_syntax *) hash_find (mem_syntax_hash,
i.maxq20_op[regnum].mem->
name);
if (mem_op->type == SRC && mem_op)
{
as_bad (_
("'%s' operand cant be used as destination in %s"),
mem_op->name, i.op.name);
return 0;
}
}
}
if (i.maxq20_op[regnum].reg->rtype == Reg_8R
|| i.maxq20_op[regnum].reg->rtype == Reg_16R)
{
as_bad (_("Read only register used for writing purposes '%s'"),
i.maxq20_op[regnum].reg->reg_name);
return 0;
}
}
if ((i.data_operands) && (i.operands == 2))
{
if ((i.types[0] != REG) && (i.types[0] != MEM))
{
as_bad (_("Invalid destination for this kind of source."));
return 0;
}
if (i.types[0] == REG && i.maxq20_op[0].reg->rtype == Reg_8W)
{
as_bad (_
("Invalid register as destination for this kind of source.Only data pointers can be used."));
return 0;
}
}
return 1;
}
static int
decode_insn (void)
{
if (i.op.format == 0 || i.op.format == 1)
i.instr[0] = i.op.format << 7;
else
{
if (i.imm_operands == 1 || i.data_operands == 1 || i.disp_operands == 1)
i.op.format = 0;
else
i.op.format = 1;
i.instr[0] = i.op.format << 7;
}
if (i.op.dst[1] == 0
&&
((i.types[0] != REG && i.types[0] != MEM && i.types[0] != BIT
&& i.operands == 2) || (i.operands < 2 && strcmp (i.op.name, "POP")
&& strcmp (i.op.name, "POPI"))
|| (i.op.arg[1] == FLAG_C)))
{
i.op.dst[0] &= 0x7f;
i.instr[0] |= i.op.dst[0];
}
else if (i.op.dst[1] == 0 && !strcmp (i.op.name, "DJNZ")
&&
(((i.types[0] == REG)
&& (!strcmp (i.maxq20_op[0].reg->reg_name, "LC[0]")
|| !strcmp (i.maxq20_op[0].reg->reg_name, "LC[1]")))))
{
i.op.dst[0] &= 0x7f;
if (!strcmp (i.maxq20_op[0].reg->reg_name, "LC[0]"))
i.instr[0] |= 0x4D;
if (!strcmp (i.maxq20_op[0].reg->reg_name, "LC[1]"))
i.instr[0] |= 0x5D;
}
else
{
unsigned char temp;
if (i.types[0] == REG
&& (i.op.dst[0] == REG || i.op.dst[0] == (REG | MEM)))
{
temp = (i.maxq20_op[0].reg)->opcode;
temp &= 0x7f;
i.instr[0] |= temp;
}
else if (i.types[0] == MEM && (i.op.dst[0] == (REG | MEM)))
{
temp = (i.maxq20_op[0].mem)->opcode;
temp &= 0x7f;
i.instr[0] |= temp;
}
else if (i.types[0] == BIT && (i.op.dst[0] == REG))
{
temp = (i.maxq20_op[0].r_bit)->reg->opcode;
temp &= 0x7f;
i.instr[0] |= temp;
}
else if (i.types[1] == BIT && (i.op.dst[0] == BIT))
{
temp = (i.maxq20_op[1].r_bit)->bit;
temp = temp << 4;
temp |= i.op.dst[1];
temp &= 0x7f;
i.instr[0] |= temp;
}
else
{
as_bad (_("Invalid Instruction"));
return 0;
}
}
if (i.operands == 0 || (i.operands == 1 && i.types[0] == FLAG)
|| (i.types[0] == FLAG && i.types[1] == IMMBIT)
|| !strcmp (i.op.name, "POP") || !strcmp (i.op.name, "POPI"))
i.instr[1] = i.op.src[0];
else if (i.imm_operands == 1 && ((i.op.src[0] & IMM) == IMM))
i.instr[1] = i.maxq20_op[this_operand].imms;
else if (i.types[this_operand] == REG && ((i.op.src[0] & REG) == REG))
i.instr[1] = (char) ((i.maxq20_op[this_operand].reg)->opcode);
else if (i.types[this_operand] == BIT && ((i.op.src[0] & REG) == REG))
i.instr[1] = (char) (i.maxq20_op[this_operand].r_bit->reg->opcode);
else if (i.types[this_operand] == MEM && ((i.op.src[0] & MEM) == MEM))
i.instr[1] = (char) ((i.maxq20_op[this_operand].mem)->opcode);
else if (i.types[this_operand] == DATA && ((i.op.src[0] & DATA) == DATA))
i.instr[1] = 0;
else if (i.op.src[1] != 0)
{
if (i.types[0] == BIT && ((i.op.src[0] & BIT) == BIT))
{
unsigned char temp = (i.maxq20_op[0].r_bit)->bit;
temp = temp << 4;
temp |= i.op.src[1];
i.instr[1] = temp;
}
else if (i.types[0] == BIT && ((i.op.src[0] & ZEROBIT) == ZEROBIT))
{
char temp = (i.maxq20_op[0].r_bit)->bit;
temp = temp << 4;
temp |= i.op.src[1];
temp &= 0x7f;
i.instr[1] = temp;
}
else if (i.types[0] == BIT && ((i.op.src[0] & ONEBIT) == ONEBIT))
{
char temp = (i.maxq20_op[0].r_bit)->bit;
temp = temp << 4;
temp |= i.op.src[1];
temp |= 0x80;
i.instr[1] = temp;
}
else if (i.types[1] == BIT)
{
if (i.op.src[1] == 0 && i.op.src[1] == REG)
i.instr[1] = (i.maxq20_op[1].r_bit)->reg->opcode;
else if (i.op.src[0] == BIT && i.op.src)
{
char temp = (i.maxq20_op[1].r_bit)->bit;
temp = temp << 4;
temp |= i.op.src[1];
i.instr[1] = temp;
}
}
else
{
as_bad (_("Invalid Instruction"));
return 0;
}
}
return 1;
}
static void
output_disp (fragS *insn_start_frag, offsetT insn_start_off)
{
char *p;
relax_substateT subtype;
symbolS *sym;
offsetT off;
int diff;
diff = 0;
insn_start_frag = frag_now;
insn_start_off = frag_now_fix ();
switch (i.Instr_Prefix)
{
case LONG_PREFIX:
subtype = EXPLICT_LONG_PREFIX;
break;
case SHORT_PREFIX:
subtype = SHORT_PREFIX;
break;
default:
subtype = NO_PREFIX;
break;
}
frag_grow (2 + 2);
p = frag_more (2);
sym = i.maxq20_op[this_operand].disps->X_add_symbol;
off = i.maxq20_op[this_operand].disps->X_add_number;
if (i.maxq20_op[this_operand].disps->X_add_symbol != NULL && sym && frag_now
&& (subtype != EXPLICT_LONG_PREFIX))
{
if (frag_now == symbol_get_frag (sym))
{
diff =
((((expressionS *) symbol_get_value_expression (sym))->
X_add_number) - insn_start_off);
diff = (diff / MAXQ_OCTETS_PER_BYTE) - 1;
if (diff >= -128 && diff <= 127)
{
i.instr[1] = (char) diff;
*p = i.instr[1];
*(p + 1) = i.instr[0];
return;
}
}
}
*p = i.instr[1];
*(p + 1) = i.instr[0];
if (i.maxq20_op[this_operand].disps->X_op != O_constant
&& i.maxq20_op[this_operand].disps->X_op != O_symbol)
{
sym = make_expr_symbol (i.maxq20_op[this_operand].disps);
off = 0;
}
if (subtype != SHORT_PREFIX)
i.reloc[this_operand] = LONG_PREFIX;
frag_var (rs_machine_dependent, 2, i.reloc[this_operand], subtype, sym, off, p);
}
static void
output_data (fragS *insn_start_frag, offsetT insn_start_off)
{
char *p;
relax_substateT subtype;
symbolS *sym;
offsetT off;
int diff;
diff = 0;
off = 0;
insn_start_frag = frag_now;
insn_start_off = frag_now_fix ();
subtype = EXPLICT_LONG_PREFIX;
frag_grow (2 + 2);
p = frag_more (2);
sym = i.maxq20_op[this_operand].data;
off = 0;
*p = i.instr[1];
*(p + 1) = i.instr[0];
if (i.maxq20_op[this_operand].disps->X_op != O_constant
&& i.maxq20_op[this_operand].disps->X_op != O_symbol)
off = 0;
frag_var (rs_machine_dependent, 2, i.reloc[this_operand], subtype, sym, off, p);
}
static void
output_insn (void)
{
fragS *insn_start_frag;
offsetT insn_start_off;
char *p;
dwarf2_emit_insn (0);
frag_align (1, 0, 1);
insn_start_frag = frag_now;
insn_start_off = frag_now_fix ();
if (i.disp_operands)
{
output_disp (insn_start_frag, insn_start_off);
return;
}
if (i.data_operands)
{
output_data (insn_start_frag, insn_start_off);
return;
}
if (strcmp (INSERT_BUFFER, ""))
{
p = frag_more (2);
*p++ = INSERT_BUFFER[1];
*p = INSERT_BUFFER[0];
}
if (strcmp (PFX_INSN, ""))
{
p = frag_more (2);
*p++ = PFX_INSN[1];
*p = PFX_INSN[0];
}
p = frag_more (2);
*p++ = i.instr[1];
*p = i.instr[0];
}
static void
make_new_reg_table (void)
{
unsigned long size_pm = sizeof (peripheral_reg_table);
num_of_reg = ARRAY_SIZE (peripheral_reg_table);
new_reg_table = xmalloc (size_pm);
if (new_reg_table == NULL)
as_bad (_("Cannot allocate memory"));
memcpy (new_reg_table, peripheral_reg_table, size_pm);
}
static void
pmmain (void)
{
make_new_reg_table ();
return;
}
void
md_begin (void)
{
const char *hash_err = NULL;
int c = 0;
char *p;
const MAXQ20_OPCODE_INFO *optab;
MAXQ20_OPCODES *core_optab;
struct reg *reg_tab;
struct mem_access_syntax const *memsyntab;
struct mem_access *memtab;
struct bit_name *bittab;
pmmain ();
op_hash = hash_new ();
optab = op_table;
core_optab = xmalloc (sizeof (MAXQ20_OPCODES));
core_optab->start = optab;
while (1)
{
++optab;
if (optab->name == NULL || strcmp (optab->name, (optab - 1)->name) != 0)
{
core_optab->end = optab;
#ifdef MAXQ10S
if (max_version == bfd_mach_maxq10)
{
if (((optab - 1)->arch == MAXQ10) || ((optab - 1)->arch == MAX))
{
hash_err = hash_insert (op_hash,
(optab - 1)->name,
(PTR) core_optab);
}
}
else if (max_version == bfd_mach_maxq20)
{
if (((optab - 1)->arch == MAXQ20) || ((optab - 1)->arch == MAX))
{
#endif
hash_err = hash_insert (op_hash,
(optab - 1)->name,
(PTR) core_optab);
#if MAXQ10S
}
}
else
as_fatal (_("Internal Error: Illegal Architecure specified"));
#endif
if (hash_err)
as_fatal (_("Internal Error: Can't hash %s: %s"),
(optab - 1)->name, hash_err);
if (optab->name == NULL)
break;
core_optab = xmalloc (sizeof (MAXQ20_OPCODES));
core_optab->start = optab;
}
}
reg_hash = hash_new ();
for (reg_tab = system_reg_table;
reg_tab < (system_reg_table + ARRAY_SIZE (system_reg_table));
reg_tab++)
{
#if MAXQ10S
switch (max_version)
{
case bfd_mach_maxq10:
if ((reg_tab->arch == MAXQ10) || (reg_tab->arch == MAX))
hash_err = hash_insert (reg_hash, reg_tab->reg_name, (PTR) reg_tab);
break;
case bfd_mach_maxq20:
if ((reg_tab->arch == MAXQ20) || (reg_tab->arch == MAX))
{
#endif
hash_err =
hash_insert (reg_hash, reg_tab->reg_name, (PTR) reg_tab);
#if MAXQ10S
}
break;
default:
as_fatal (_("Invalid architecture type"));
}
#endif
if (hash_err)
as_fatal (_("Internal Error : Can't Hash %s : %s"),
reg_tab->reg_name, hash_err);
}
for (reg_tab = new_reg_table;
reg_tab < (new_reg_table + num_of_reg - 1); reg_tab++)
{
hash_err = hash_insert (reg_hash, reg_tab->reg_name, (PTR) reg_tab);
if (hash_err)
as_fatal (_("Internal Error : Can't Hash %s : %s"),
reg_tab->reg_name, hash_err);
}
mem_hash = hash_new ();
for (memtab = mem_table;
memtab < mem_table + ARRAY_SIZE (mem_table);
memtab++)
{
hash_err = hash_insert (mem_hash, memtab->name, (PTR) memtab);
if (hash_err)
as_fatal (_("Internal Error : Can't Hash %s : %s"),
memtab->name, hash_err);
}
bit_hash = hash_new ();
for (bittab = bit_table;
bittab < bit_table + ARRAY_SIZE (bit_table);
bittab++)
{
hash_err = hash_insert (bit_hash, bittab->name, (PTR) bittab);
if (hash_err)
as_fatal (_("Internal Error : Can't Hash %s : %s"),
bittab->name, hash_err);
}
mem_syntax_hash = hash_new ();
for (memsyntab = mem_access_syntax_table;
memsyntab < mem_access_syntax_table + ARRAY_SIZE (mem_access_syntax_table);
memsyntab++)
{
hash_err =
hash_insert (mem_syntax_hash, memsyntab->name, (PTR) memsyntab);
if (hash_err)
as_fatal (_("Internal Error : Can't Hash %s : %s"),
memsyntab->name, hash_err);
}
for (c = 0; c < 256; c++)
{
if (ISDIGIT (c))
{
digit_chars[c] = c;
mnemonic_chars[c] = c;
operand_chars[c] = c;
register_chars[c] = c;
}
else if (ISLOWER (c))
{
mnemonic_chars[c] = c;
operand_chars[c] = c;
register_chars[c] = c;
}
else if (ISUPPER (c))
{
mnemonic_chars[c] = TOLOWER (c);
register_chars[c] = c;
operand_chars[c] = c;
}
if (ISALPHA (c) || ISDIGIT (c))
{
identifier_chars[c] = c;
}
else if (c > 128)
{
identifier_chars[c] = c;
operand_chars[c] = c;
}
}
register_chars['@'] = '@';
register_chars['+'] = '+';
register_chars['-'] = '-';
digit_chars['-'] = '-';
identifier_chars['_'] = '_';
identifier_chars['.'] = '.';
register_chars['['] = '[';
register_chars[']'] = ']';
operand_chars['_'] = '_';
operand_chars['#'] = '#';
mnemonic_chars['['] = '[';
mnemonic_chars[']'] = ']';
for (p = operand_special_chars; *p != '\0'; p++)
operand_chars[(unsigned char) *p] = (unsigned char) *p;
maxq_target (max_version);
}
void
md_assemble (char *line)
{
int j;
char mnemonic[MAX_MNEM_SIZE];
char temp4prev[256];
static char prev_insn[256];
memset (&i, '\0', sizeof (i));
for (j = 0; j < MAX_OPERANDS; j++)
i.reloc[j] = NO_RELOC;
i.prefix = -1;
PFX_INSN[0] = 0;
PFX_INSN[1] = 0;
INSERT_BUFFER[0] = 0;
INSERT_BUFFER[1] = 0;
memcpy (temp4prev, line, strlen (line) + 1);
save_stack_p = save_stack;
line = (char *) parse_insn (line, mnemonic);
if (line == NULL)
return;
line = (char *) parse_operands (line, mnemonic);
if (line == NULL)
return;
if (!match_template ())
return;
if (!match_filters ())
return;
set_prefix ();
pfx_for_imm_val (0);
if (!decode_insn ())
need_pass_2 = 1;
if (PFX_INSN[0] && (strstr (prev_insn, "PFX") || strstr (prev_insn, "pfx")))
as_warn (_("Ineffective insntruction %s \n"), prev_insn);
memcpy (prev_insn, temp4prev, strlen (temp4prev) + 1);
output_insn ();
}