daily update
[external/binutils.git] / gas / config / tc-tic4x.c
index dbd71d0..bc92de2 100644 (file)
@@ -1,5 +1,6 @@
-/* tc-c4x.c -- Assemble for the Texas Instruments TMS320C[34]x.
-   Copyright (C) 1997,1998, 2002 Free Software Foundation.
+/* tc-tic4x.c -- Assemble for the Texas Instruments TMS320C[34]x.
+   Copyright (C) 1997,1998, 2002, 2003, 2005, 2006, 2007, 2008
+   Free Software Foundation. Inc.
 
    Contributed by Michael P. Hayes (m.hayes@elec.canterbury.ac.nz)
 
@@ -7,7 +8,7 @@
 
    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)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GAS is distributed in the hope that it will be useful,
 
    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.  */
+   the Free Software Foundation, 51 Franklin Street - Fifth Floor, 
+   Boston, MA 02110-1301, USA.  */
+/*
+  TODOs:
+  ------
+  
+  o .align cannot handle fill-data-width larger than 0xFF/8-bits. It
+    should be possible to define a 32-bits pattern.
 
+  o .align fills all section with NOP's when used regardless if has
+    been used in .text or .data. (However the .align is primarily
+    intended used in .text sections. If you require something else,
+    use .align <size>,0x00)
 
-/* Things not currently implemented:
-   > .usect if has symbol on previous line  
+  o .align: Implement a 'bu' insn if the number of nop's exceeds 4
+    within the align frag. if(fragsize>4words) insert bu fragend+1
+    first.
 
-   > .sym, .eos, .stag, .etag, .member
+  o .usect if has symbol on previous line not implemented
 
-   > Evaluation of constant floating point expressions (expr.c needs work!)
+  o .sym, .eos, .stag, .etag, .member not implemented
 
-   > Warnings issued if parallel load of same register
+  o Evaluation of constant floating point expressions (expr.c needs
+    work!)
 
-   Note that this is primarily designed to handle the code generated
-   by GCC.  Anything else is a bonus!  */
-
-#include <stdio.h>
-#include <ctype.h>
+  o Support 'abc' constants (that is 0x616263)
+*/
 
+#include "safe-ctype.h"
 #include "as.h"
 #include "opcode/tic4x.h"
 #include "subsegs.h"
 #include "obstack.h"
-#include "symbols.h"
-#include "listing.h"
 
 /* OK, we accept a syntax similar to the other well known C30
-   assembly tools.  With C4X_ALT_SYNTAX defined we are more
+   assembly tools.  With TIC4X_ALT_SYNTAX defined we are more
    flexible, allowing a more Unix-like syntax:  `%' in front of
    register names, `#' in front of immediate constants, and
    not requiring `@' in front of direct addresses.  */
 
-#define C4X_ALT_SYNTAX
+#define TIC4X_ALT_SYNTAX
 
 /* Equal to MAX_PRECISION in atof-ieee.c.  */
 #define MAX_LITTLENUMS 6       /* (12 bytes) */
 
 /* Handle of the inst mnemonic hash table.  */
-static struct hash_control *c4x_op_hash = NULL;
+static struct hash_control *tic4x_op_hash = NULL;
 
 /* Handle asg pseudo.  */
-static struct hash_control *c4x_asg_hash = NULL;
+static struct hash_control *tic4x_asg_hash = NULL;
+
+static unsigned int tic4x_cpu = 0;        /* Default to TMS320C40.  */
+static unsigned int tic4x_revision = 0;   /* CPU revision */
+static unsigned int tic4x_idle2 = 0;      /* Idle2 support */
+static unsigned int tic4x_lowpower = 0;   /* Lowpower support */
+static unsigned int tic4x_enhanced = 0;   /* Enhanced opcode support */
+static unsigned int tic4x_big_model = 0;  /* Default to small memory model.  */
+static unsigned int tic4x_reg_args = 0;   /* Default to args passed on stack.  */
+static unsigned long tic4x_oplevel = 0;   /* Opcode level */
+
+#define OPTION_CPU      'm'
+#define OPTION_BIG      (OPTION_MD_BASE + 1)
+#define OPTION_SMALL    (OPTION_MD_BASE + 2)
+#define OPTION_MEMPARM  (OPTION_MD_BASE + 3)
+#define OPTION_REGPARM  (OPTION_MD_BASE + 4)
+#define OPTION_IDLE2    (OPTION_MD_BASE + 5)
+#define OPTION_LOWPOWER (OPTION_MD_BASE + 6)
+#define OPTION_ENHANCED (OPTION_MD_BASE + 7)
+#define OPTION_REV      (OPTION_MD_BASE + 8)
+
+CONST char *md_shortopts = "bm:prs";
+struct option md_longopts[] =
+{
+  { "mcpu",   required_argument, NULL, OPTION_CPU },
+  { "mdsp",   required_argument, NULL, OPTION_CPU },
+  { "mbig",         no_argument, NULL, OPTION_BIG },
+  { "msmall",       no_argument, NULL, OPTION_SMALL },
+  { "mmemparm",     no_argument, NULL, OPTION_MEMPARM },
+  { "mregparm",     no_argument, NULL, OPTION_REGPARM },
+  { "midle2",       no_argument, NULL, OPTION_IDLE2 },
+  { "mlowpower",    no_argument, NULL, OPTION_LOWPOWER },
+  { "menhanced",    no_argument, NULL, OPTION_ENHANCED },
+  { "mrev",   required_argument, NULL, OPTION_REV },
+  { NULL, no_argument, NULL, 0 }
+};
+
+size_t md_longopts_size = sizeof (md_longopts);
 
-static unsigned int c4x_cpu = 0;       /* Default to TMS320C40.  */
-static unsigned int c4x_big_model = 0; /* Default to small memory model.  */
-static unsigned int c4x_reg_args = 0;  /* Default to args passed on stack.  */
 
 typedef enum
   {
     M_UNKNOWN, M_IMMED, M_DIRECT, M_REGISTER, M_INDIRECT,
     M_IMMED_F, M_PARALLEL, M_HI
   }
-c4x_addr_mode_t;
+tic4x_addr_mode_t;
 
-typedef struct c4x_operand
+typedef struct tic4x_operand
   {
-    c4x_addr_mode_t mode;      /* Addressing mode.  */
+    tic4x_addr_mode_t mode;    /* Addressing mode.  */
     expressionS expr;          /* Expression.  */
     int disp;                  /* Displacement for indirect addressing.  */
     int aregno;                        /* Aux. register number.  */
     LITTLENUM_TYPE fwords[MAX_LITTLENUMS];     /* Float immed. number.  */
   }
-c4x_operand_t;
+tic4x_operand_t;
 
-typedef struct c4x_insn
+typedef struct tic4x_insn
   {
-    char name[C4X_NAME_MAX];   /* Mnemonic of instruction.  */
+    char name[TIC4X_NAME_MAX]; /* Mnemonic of instruction.  */
     unsigned int in_use;       /* True if in_use.  */
     unsigned int parallel;     /* True if parallel instruction.  */
     unsigned int nchars;       /* This is always 4 for the C30.  */
@@ -93,77 +136,66 @@ typedef struct c4x_insn
     int pcrel;                 /* True if relocation PC relative.  */
     char *pname;               /* Name of instruction in parallel.  */
     unsigned int num_operands; /* Number of operands in total.  */
-    c4x_inst_t *inst;          /* Pointer to first template.  */
-    c4x_operand_t operands[C4X_OPERANDS_MAX];
+    tic4x_inst_t *inst;                /* Pointer to first template.  */
+    tic4x_operand_t operands[TIC4X_OPERANDS_MAX];
   }
-c4x_insn_t;
-
-static c4x_insn_t the_insn;    /* Info about our instruction.  */
-static c4x_insn_t *insn = &the_insn;
-
-static void c4x_asg PARAMS ((int));
-static void c4x_bss PARAMS ((int));
-static void c4x_globl PARAMS ((int));
-static void c4x_eval PARAMS ((int));
-static void c4x_cons PARAMS ((int));
-static void c4x_set PARAMS ((int));
-static void c4x_newblock PARAMS ((int));
-static void c4x_pseudo_ignore PARAMS ((int));
-static void c4x_sect PARAMS ((int));
-static void c4x_usect PARAMS ((int));
-static void c4x_version PARAMS ((int));
+tic4x_insn_t;
+
+static tic4x_insn_t the_insn;  /* Info about our instruction.  */
+static tic4x_insn_t *insn = &the_insn;
+
+static void tic4x_asg (int);
+static void tic4x_bss (int);
+static void tic4x_globl (int);
+static void tic4x_cons (int);
+static void tic4x_stringer (int);
+static void tic4x_eval (int);
+static void tic4x_newblock (int);
+static void tic4x_sect (int);
+static void tic4x_set (int);
+static void tic4x_usect (int);
+static void tic4x_version (int);
+
 
 const pseudo_typeS
   md_pseudo_table[] =
 {
   {"align", s_align_bytes, 32},
-  {"ascii", c4x_cons, 1},
-  {"asciz", c4x_pseudo_ignore, 0},
-  {"asg", c4x_asg, 0},
-  {"asect", c4x_pseudo_ignore, 0}, /* Absolute named section.  */
-  {"block", s_space, 0},
-  {"byte", c4x_cons, 1},
-  {"bss", c4x_bss, 0},
-  {"comm", c4x_bss, 0},
-  {"def", c4x_globl, 0},
-  {"endfunc", c4x_pseudo_ignore, 0},
-  {"eos", c4x_pseudo_ignore, 0},
-  {"etag", c4x_pseudo_ignore, 0},
-  {"equ", c4x_set, 0},
-  {"eval", c4x_eval, 0},
-  {"exitm", s_mexit, 0},
-  {"func", c4x_pseudo_ignore, 0},
-  {"global", c4x_globl, 0},
-  {"globl", c4x_globl, 0},
-  {"hword", c4x_cons, 2},
+  {"ascii", tic4x_stringer, 1},
+  {"asciz", tic4x_stringer, 0},
+  {"asg", tic4x_asg, 0},
+  {"block", s_space, 4},
+  {"byte", tic4x_cons, 1},
+  {"bss", tic4x_bss, 0},
+  {"copy", s_include, 0},
+  {"def", tic4x_globl, 0},
+  {"equ", tic4x_set, 0},
+  {"eval", tic4x_eval, 0},
+  {"global", tic4x_globl, 0},
+  {"globl", tic4x_globl, 0},
+  {"hword", tic4x_cons, 2},
   {"ieee", float_cons, 'i'},
-  {"int", c4x_cons, 4},                /* .int allocates 4 bytes.  */
-  {"length", c4x_pseudo_ignore, 0},
-  {"ldouble", float_cons, 'l'},
-  {"member", c4x_pseudo_ignore, 0},
-  {"newblock", c4x_newblock, 0},
-  {"ref", s_ignore, 0},                /* All undefined treated as external.  */
-  {"set", c4x_set, 0},
-  {"sect", c4x_sect, 1},       /* Define named section.  */
+  {"int", tic4x_cons, 4},               /* .int allocates 4 bytes.  */
+  {"ldouble", float_cons, 'e'},
+  {"newblock", tic4x_newblock, 0},
+  {"ref", s_ignore, 0},                 /* All undefined treated as external.  */
+  {"set", tic4x_set, 0},
+  {"sect", tic4x_sect, 1},      /* Define named section.  */
   {"space", s_space, 4},
-  {"stag", c4x_pseudo_ignore, 0},
-  {"string", c4x_pseudo_ignore, 0},
-  {"sym", c4x_pseudo_ignore, 0},
-  {"usect", c4x_usect, 0},     /* Reserve space in uninit. named sect.  */
-  {"version", c4x_version, 0},
-  {"width", c4x_pseudo_ignore, 0},
-  {"word", c4x_cons, 4},       /* .word allocates 4 bytes.  */
-  {"xdef", c4x_globl, 0},
+  {"string", tic4x_stringer, 0},
+  {"usect", tic4x_usect, 0},       /* Reserve space in uninit. named sect.  */
+  {"version", tic4x_version, 0},
+  {"word", tic4x_cons, 4},      /* .word allocates 4 bytes.  */
+  {"xdef", tic4x_globl, 0},
   {NULL, 0, 0},
 };
 
 int md_short_jump_size = 4;
 int md_long_jump_size = 4;
-const int md_reloc_size = RELSZ;       /* Coff headers.  */
 
 /* This array holds the chars that always start a comment.  If the
    pre-processor is disabled, these aren't very useful.  */
-#ifdef C4X_ALT_SYNTAX
+#ifdef TIC4X_ALT_SYNTAX
 const char comment_chars[] = ";!";
 #else
 const char comment_chars[] = ";";
@@ -198,14 +230,16 @@ const char FLT_CHARS[] = "fFilsS";
 extern FLONUM_TYPE generic_floating_point_number;
 
 /* Precision in LittleNums.  */
-#define MAX_PRECISION (2)
+#define MAX_PRECISION (4)       /* Its a bit overkill for us, but the code
+                                   requires it... */
 #define S_PRECISION (1)                /* Short float constants 16-bit.  */
 #define F_PRECISION (2)                /* Float and double types 32-bit.  */
+#define E_PRECISION (4)         /* Extended precision, 64-bit (real 40-bit). */
 #define GUARD (2)
 
 /* Turn generic_floating_point_number into a real short/float/double.  */
-int
-c4x_gen_to_words (FLONUM_TYPE flonum, LITTLENUM_TYPE *words, int precision)
+static int
+tic4x_gen_to_words (FLONUM_TYPE flonum, LITTLENUM_TYPE *words, int precision)
 {
   int return_value = 0;
   LITTLENUM_TYPE *p;           /* Littlenum pointer.  */
@@ -216,9 +250,17 @@ c4x_gen_to_words (FLONUM_TYPE flonum, LITTLENUM_TYPE *words, int precision)
   unsigned int sfract;         /* Scaled fraction.  */
   unsigned int smant;          /* Scaled mantissa.  */
   unsigned int tmp;
+  unsigned int mover;           /* Mantissa overflow bits */
+  unsigned int rbit;            /* Round bit. */
   int shift;                   /* Shift count.  */
 
-  /* Here is how a generic floating point number is stored using
+  /* NOTE: Svein Seldal <Svein@dev.seldal.com>
+     The code in this function is altered slightly to support floats
+     with 31-bits mantissas, thus the documentation below may be a
+     little bit inaccurate.
+     
+     By Michael P. Hayes <m.hayes@elec.canterbury.ac.nz>
+     Here is how a generic floating point number is stored using
      flonums (an extension of bignums) where p is a pointer to an
      array of LITTLENUMs.
 
@@ -323,7 +365,7 @@ c4x_gen_to_words (FLONUM_TYPE flonum, LITTLENUM_TYPE *words, int precision)
 
      We now have to left shift the other littlenums by the same amount,
      propagating the shifted bits into the more significant littlenums.
-     To save a lot of unecessary shifting we only have to consider
+     To save a lot of unnecessary shifting we only have to consider
      two or three littlenums, since the greatest number of mantissa
      bits required is 24 + 1 rounding bit.  While two littlenums
      provide 32 bits of precision, the most significant littlenum
@@ -346,31 +388,34 @@ c4x_gen_to_words (FLONUM_TYPE flonum, LITTLENUM_TYPE *words, int precision)
 
   if (precision != S_PRECISION)
     words[1] = 0x0000;
+  if (precision == E_PRECISION)
+    words[2] = words[3] = 0x0000;
 
-  /* 0.0e0 seen.  */
-  if (flonum.low > flonum.leader)
+  /* 0.0e0 or NaN seen.  */
+  if (flonum.low > flonum.leader  /* = 0.0e0 */
+      || flonum.sign == 0) /* = NaN */
     {
+      if(flonum.sign == 0)
+        as_bad ("Nan, using zero.");
       words[0] = 0x8000;
       return return_value;
     }
 
-  /* NaN:  We can't do much...  */
-  if (flonum.sign == 0)
-    {
-      as_bad ("Nan, using zero.");
-      words[0] = 0x8000;
-      return return_value;
-    }
-  else if (flonum.sign == 'P')
+  if (flonum.sign == 'P')
     {
       /* +INF:  Replace with maximum float.  */
       if (precision == S_PRECISION)
        words[0] = 0x77ff;
-      else
+      else 
        {
          words[0] = 0x7f7f;
          words[1] = 0xffff;
        }
+      if (precision == E_PRECISION)
+        {
+          words[2] = 0x7fff;
+          words[3] = 0xffff;
+        }
       return return_value;
     }
   else if (flonum.sign == 'N')
@@ -378,8 +423,10 @@ c4x_gen_to_words (FLONUM_TYPE flonum, LITTLENUM_TYPE *words, int precision)
       /* -INF:  Replace with maximum float.  */
       if (precision == S_PRECISION)
        words[0] = 0x7800;
-      else
-       words[0] = 0x7f80;
+      else 
+        words[0] = 0x7f80;
+      if (precision == E_PRECISION)
+        words[2] = 0x8000;
       return return_value;
     }
 
@@ -395,43 +442,64 @@ c4x_gen_to_words (FLONUM_TYPE flonum, LITTLENUM_TYPE *words, int precision)
   if (precision == S_PRECISION)        /* Allow 1 rounding bit.  */
     {
       exponent_bits = 4;
-      mantissa_bits = 12;      /* Include suppr. bit but not rounding bit.  */
+      mantissa_bits = 11;
     }
-  else
+  else if(precision == F_PRECISION)
+    {
+      exponent_bits = 8;
+      mantissa_bits = 23;
+    }
+  else /* E_PRECISION */
     {
       exponent_bits = 8;
-      mantissa_bits = 24;
+      mantissa_bits = 31;
     }
 
   shift = mantissa_bits - shift;
 
   smant = 0;
+  mover = 0;
+  rbit = 0;
+  /* Store the mantissa data into smant and the roundbit into rbit */
   for (p = flonum.leader; p >= flonum.low && shift > -16; p--)
     {
       tmp = shift >= 0 ? *p << shift : *p >> -shift;
+      rbit = shift < 0 ? ((*p >> (-shift-1)) & 0x1) : 0;
       smant |= tmp;
       shift -= 16;
     }
 
-  /* OK, we've got our scaled mantissa so let's round it up
-     and drop the rounding bit.  */
-  smant++;
-  smant >>= 1;
+  /* OK, we've got our scaled mantissa so let's round it up */
+  if(rbit)
+    {
+      /* If the mantissa is going to overflow when added, lets store
+         the extra bit in mover. -- A special case exists when
+         mantissa_bits is 31 (E_PRECISION). Then the first test cannot
+         be trusted, as result is host-dependent, thus the second
+         test. */
+      if( smant == ((unsigned)(1<<(mantissa_bits+1))-1)
+          || smant == (unsigned)-1 )  /* This is to catch E_PRECISION cases */
+        mover=1;
+      smant++;
+    }
+
+  /* Get the scaled one value */
+  sone = (1 << (mantissa_bits));
 
   /* The number may be unnormalised so renormalise it...  */
-  if (smant >> mantissa_bits)
+  if(mover)
     {
       smant >>= 1;
+      smant |= sone; /* Insert the bit from mover into smant */
       exponent++;
     }
 
   /* The binary point is now between bit positions 11 and 10 or 23 and 22,
      i.e., between mantissa_bits - 1 and mantissa_bits - 2 and the
      bit at mantissa_bits - 1 should be set.  */
-  if (!(smant >> (mantissa_bits - 1)))
-    abort ();                  /* Ooops.  */
+  if (!(sone&smant))
+    abort ();                   /* Ooops.  */
 
-  sone = (1 << (mantissa_bits - 1));
   if (flonum.sign == '+')
     sfract = smant - sone;     /* smant - 1.0.  */
   else
@@ -443,7 +511,9 @@ c4x_gen_to_words (FLONUM_TYPE flonum, LITTLENUM_TYPE *words, int precision)
          sfract = 0;
        }
       else
-       sfract = (sone << 1) - smant;   /* 2.0 - smant.  */
+        {
+          sfract = -smant & (sone-1);   /* 2.0 - smant.  */
+        }
       sfract |= sone;          /* Insert sign bit.  */
     }
 
@@ -452,22 +522,38 @@ c4x_gen_to_words (FLONUM_TYPE flonum, LITTLENUM_TYPE *words, int precision)
 
   /* Force exponent to fit in desired field width.  */
   exponent &= (1 << (exponent_bits)) - 1;
-  sfract |= exponent << mantissa_bits;
 
-  if (precision == S_PRECISION)
-    words[0] = sfract;
+  if (precision == E_PRECISION)
+    {
+      /* Map the float part first (100% equal format as F_PRECISION) */
+      words[0]  = exponent << (mantissa_bits+1-24);
+      words[0] |= sfract >> 24;
+      words[1]  = sfract >> 8;
+
+      /* Map the mantissa in the next */
+      words[2]  = sfract >> 16;
+      words[3]  = sfract & 0xffff;
+    }
   else
     {
-      words[0] = sfract >> 16;
-      words[1] = sfract & 0xffff;
+      /* Insert the exponent data into the word */
+      sfract |= exponent << (mantissa_bits+1);
+
+      if (precision == S_PRECISION)
+        words[0] = sfract;
+      else
+        {
+          words[0] = sfract >> 16;
+          words[1] = sfract & 0xffff;
+        }
     }
 
   return return_value;
 }
 
 /* Returns pointer past text consumed.  */
-char *
-c4x_atof (char *str, char what_kind, LITTLENUM_TYPE *words)
+static char *
+tic4x_atof (char *str, char what_kind, LITTLENUM_TYPE *words)
 {
   /* Extra bits for zeroed low-order bits.  The 1st MAX_PRECISION are
      zeroed, the last contain flonum bits.  */
@@ -509,6 +595,11 @@ c4x_atof (char *str, char what_kind, LITTLENUM_TYPE *words)
       precision = F_PRECISION;
       break;
 
+    case 'E':
+    case 'e':
+      precision = E_PRECISION;
+      break;
+
     default:
       as_bad ("Invalid floating point number");
       return (NULL);
@@ -524,7 +615,7 @@ c4x_atof (char *str, char what_kind, LITTLENUM_TYPE *words)
       return (NULL);
     }
 
-  c4x_gen_to_words (generic_floating_point_number,
+  tic4x_gen_to_words (generic_floating_point_number,
                    words, precision);
 
   /* Restore the generic_floating_point_number's storage alloc (and
@@ -535,7 +626,7 @@ c4x_atof (char *str, char what_kind, LITTLENUM_TYPE *words)
 }
 
 static void 
-c4x_insert_reg (char *regname, int regnum)
+tic4x_insert_reg (char *regname, int regnum)
 {
   char buf[32];
   int i;
@@ -543,7 +634,7 @@ c4x_insert_reg (char *regname, int regnum)
   symbol_table_insert (symbol_new (regname, reg_section, (valueT) regnum,
                                   &zero_address_frag));
   for (i = 0; regname[i]; i++)
-    buf[i] = islower (regname[i]) ? toupper (regname[i]) : regname[i];
+    buf[i] = ISLOWER (regname[i]) ? TOUPPER (regname[i]) : regname[i];
   buf[i] = '\0';
 
   symbol_table_insert (symbol_new (buf, reg_section, (valueT) regnum,
@@ -551,7 +642,7 @@ c4x_insert_reg (char *regname, int regnum)
 }
 
 static void 
-c4x_insert_sym (char *symname, int value)
+tic4x_insert_sym (char *symname, int value)
 {
   symbolS *symbolP;
 
@@ -562,7 +653,7 @@ c4x_insert_sym (char *symname, int value)
 }
 
 static char *
-c4x_expression (char *str, expressionS *exp)
+tic4x_expression (char *str, expressionS *exp)
 {
   char *s;
   char *t;
@@ -576,7 +667,7 @@ c4x_expression (char *str, expressionS *exp)
 }
 
 static char *
-c4x_expression_abs (char *str, int *value)
+tic4x_expression_abs (char *str, offsetT *value)
 {
   char *s;
   char *t;
@@ -590,17 +681,20 @@ c4x_expression_abs (char *str, int *value)
 }
 
 static void 
-c4x_emit_char (char c)
+tic4x_emit_char (char c, int b)
 {
   expressionS exp;
 
   exp.X_op = O_constant;
   exp.X_add_number = c;
-  emit_expr (&exp, 4);
+  emit_expr (&exp, b);
 }
 
 static void 
-c4x_seg_alloc (char *name, segT seg, int size, symbolS *symbolP)
+tic4x_seg_alloc (char *name ATTRIBUTE_UNUSED,
+                segT seg ATTRIBUTE_UNUSED,
+                int size,
+                symbolS *symbolP)
 {
   /* Note that the size is in words
      so we multiply it by 4 to get the number of bytes to allocate.  */
@@ -622,7 +716,7 @@ c4x_seg_alloc (char *name, segT seg, int size, symbolS *symbolP)
 
 /* .asg ["]character-string["], symbol */
 static void 
-c4x_asg (int x)
+tic4x_asg (int x ATTRIBUTE_UNUSED)
 {
   char c;
   char *name;
@@ -649,22 +743,22 @@ c4x_asg (int x)
   tmp = xmalloc (strlen (name) + 1);
   strcpy (tmp, name);
   name = tmp;
-  if (hash_find (c4x_asg_hash, name))
-    hash_replace (c4x_asg_hash, name, (PTR) str);
+  if (hash_find (tic4x_asg_hash, name))
+    hash_replace (tic4x_asg_hash, name, (void *) str);
   else
-    hash_insert (c4x_asg_hash, name, (PTR) str);
+    hash_insert (tic4x_asg_hash, name, (void *) str);
   *input_line_pointer = c;
   demand_empty_rest_of_line ();
 }
 
 /* .bss symbol, size  */
 static void 
-c4x_bss (int x)
+tic4x_bss (int x ATTRIBUTE_UNUSED)
 {
   char c;
   char *name;
   char *p;
-  int size;
+  offsetT size;
   segT current_seg;
   subsegT current_subseg;
   symbolS *symbolP;
@@ -682,10 +776,10 @@ c4x_bss (int x)
     }
 
   input_line_pointer =
-    c4x_expression_abs (++input_line_pointer, &size);
+    tic4x_expression_abs (++input_line_pointer, &size);
   if (size < 0)
     {
-      as_bad (".bss size %d < 0!", size);
+      as_bad (".bss size %ld < 0!", (long) size);
       return;
     }
   subseg_set (bss_section, 0);
@@ -712,8 +806,8 @@ c4x_bss (int x)
   demand_empty_rest_of_line ();
 }
 
-void
-c4x_globl (int ignore)
+static void
+tic4x_globl (int ignore ATTRIBUTE_UNUSED)
 {
   char *name;
   int c;
@@ -727,6 +821,7 @@ c4x_globl (int ignore)
       *input_line_pointer = c;
       SKIP_WHITESPACE ();
       S_SET_STORAGE_CLASS (symbolP, C_EXT);
+      S_SET_EXTERNAL (symbolP);
       if (c == ',')
        {
          input_line_pointer++;
@@ -742,7 +837,7 @@ c4x_globl (int ignore)
 
 /* Handle .byte, .word. .int, .long */
 static void 
-c4x_cons (int bytes)
+tic4x_cons (int bytes)
 {
   register unsigned int c;
   do
@@ -752,14 +847,14 @@ c4x_cons (int bytes)
        {
          input_line_pointer++;
          while (is_a_char (c = next_char_of_string ()))
-           c4x_emit_char (c);
+           tic4x_emit_char (c, 4);
          know (input_line_pointer[-1] == '\"');
        }
       else
        {
          expressionS exp;
 
-         input_line_pointer = c4x_expression (input_line_pointer, &exp);
+         input_line_pointer = tic4x_expression (input_line_pointer, &exp);
          if (exp.X_op == O_constant)
            {
              switch (bytes)
@@ -783,17 +878,70 @@ c4x_cons (int bytes)
   demand_empty_rest_of_line ();
 }
 
+/* Handle .ascii, .asciz, .string */
+static void 
+tic4x_stringer (int append_zero)
+{
+  int bytes;
+  register unsigned int c;
+
+  bytes = 0;
+  do
+    {
+      SKIP_WHITESPACE ();
+      if (*input_line_pointer == '"')
+       {
+         input_line_pointer++;
+         while (is_a_char (c = next_char_of_string ()))
+            {
+              tic4x_emit_char (c, 1);
+              bytes++;
+            }
+
+          if (append_zero)
+            {
+              tic4x_emit_char (c, 1);
+              bytes++;
+            }
+
+         know (input_line_pointer[-1] == '\"');
+       }
+      else
+       {
+         expressionS exp;
+
+         input_line_pointer = tic4x_expression (input_line_pointer, &exp);
+         if (exp.X_op != O_constant)
+            {
+              as_bad("Non-constant symbols not allowed\n");
+              return;
+            }
+          exp.X_add_number &= 255; /* Limit numeber to 8-bit */
+         emit_expr (&exp, 1);
+          bytes++;
+       }
+    }
+  while (*input_line_pointer++ == ',');
+
+  /* Fill out the rest of the expression with 0's to fill up a full word */
+  if ( bytes&0x3 )
+    tic4x_emit_char (0, 4-(bytes&0x3));
+
+  input_line_pointer--;                /* Put terminator back into stream.  */
+  demand_empty_rest_of_line ();
+}
+
 /* .eval expression, symbol */
 static void 
-c4x_eval (int x)
+tic4x_eval (int x ATTRIBUTE_UNUSED)
 {
   char c;
-  int value;
+  offsetT value;
   char *name;
 
   SKIP_WHITESPACE ();
   input_line_pointer =
-    c4x_expression_abs (input_line_pointer, &value);
+    tic4x_expression_abs (input_line_pointer, &value);
   if (*input_line_pointer++ != ',')
     {
       as_bad ("Symbol missing\n");
@@ -802,12 +950,12 @@ c4x_eval (int x)
   name = input_line_pointer;
   c = get_symbol_end ();       /* Get terminator.  */
   demand_empty_rest_of_line ();
-  c4x_insert_sym (name, value);
+  tic4x_insert_sym (name, value);
 }
 
 /* Reset local labels.  */
 static void 
-c4x_newblock (int x)
+tic4x_newblock (int x ATTRIBUTE_UNUSED)
 {
   dollar_label_clear ();
 }
@@ -815,14 +963,14 @@ c4x_newblock (int x)
 /* .sect "section-name" [, value] */
 /* .sect ["]section-name[:subsection-name]["] [, value] */
 static void 
-c4x_sect (int x)
+tic4x_sect (int x ATTRIBUTE_UNUSED)
 {
   char c;
   char *section_name;
   char *subsection_name;
   char *name;
   segT seg;
-  int num;
+  offsetT num;
 
   SKIP_WHITESPACE ();
   if (*input_line_pointer == '"')
@@ -852,11 +1000,11 @@ c4x_sect (int x)
 
   if (c == ',')
     input_line_pointer =
-      c4x_expression_abs (input_line_pointer, &num);
+      tic4x_expression_abs (input_line_pointer, &num);
   else if (*input_line_pointer == ',')
     {
       input_line_pointer =
-       c4x_expression_abs (++input_line_pointer, &num);
+       tic4x_expression_abs (++input_line_pointer, &num);
     }
   else
     num = 0;
@@ -888,7 +1036,7 @@ c4x_sect (int x)
 
 /* symbol[:] .set value  or  .set symbol, value */
 static void 
-c4x_set (int x)
+tic4x_set (int x ATTRIBUTE_UNUSED)
 {
   symbolS *symbolP;
 
@@ -906,6 +1054,7 @@ c4x_set (int x)
          ignore_rest_of_line ();
          return;
        }
+      ++input_line_pointer;
       symbolP = symbol_find_or_make (name);
     }
   else
@@ -917,13 +1066,13 @@ c4x_set (int x)
 
 /* [symbol] .usect ["]section-name["], size-in-words [, alignment-flag] */
 static void 
-c4x_usect (int x)
+tic4x_usect (int x ATTRIBUTE_UNUSED)
 {
   char c;
   char *name;
   char *section_name;
   segT seg;
-  int size, alignment_flag;
+  offsetT size, alignment_flag;
   segT current_seg;
   subsegT current_subseg;
 
@@ -941,11 +1090,11 @@ c4x_usect (int x)
 
   if (c == ',')
     input_line_pointer =
-      c4x_expression_abs (input_line_pointer, &size);
+      tic4x_expression_abs (input_line_pointer, &size);
   else if (*input_line_pointer == ',')
     {
       input_line_pointer =
-       c4x_expression_abs (++input_line_pointer, &size);
+       tic4x_expression_abs (++input_line_pointer, &size);
     }
   else
     size = 0;
@@ -954,7 +1103,7 @@ c4x_usect (int x)
   if (*input_line_pointer == ',')
     {
       input_line_pointer =
-       c4x_expression_abs (++input_line_pointer, &alignment_flag);
+       tic4x_expression_abs (++input_line_pointer, &alignment_flag);
     }
   else
     alignment_flag = 0;
@@ -972,7 +1121,7 @@ c4x_usect (int x)
   if (!bfd_set_section_flags (stdoutput, seg, SEC_ALLOC))
     as_warn ("Error setting flags for \"%s\": %s", name,
             bfd_errmsg (bfd_get_error ()));
-  c4x_seg_alloc (name, seg, size, line_label);
+  tic4x_seg_alloc (name, seg, size, line_label);
 
   if (S_GET_STORAGE_CLASS (line_label) != C_EXT)
     S_SET_STORAGE_CLASS (line_label, C_STAT);
@@ -983,51 +1132,42 @@ c4x_usect (int x)
 
 /* .version cpu-version.  */
 static void 
-c4x_version (int x)
+tic4x_version (int x ATTRIBUTE_UNUSED)
 {
-  unsigned int temp;
+  offsetT temp;
 
   input_line_pointer =
-    c4x_expression_abs (input_line_pointer, &temp);
-  if (!IS_CPU_C3X (temp) && !IS_CPU_C4X (temp))
-    as_bad ("This assembler does not support processor generation %d\n",
-           temp);
-
-  if (c4x_cpu && temp != c4x_cpu)
-    as_warn ("Changing processor generation on fly not supported...\n");
-  c4x_cpu = temp;
+    tic4x_expression_abs (input_line_pointer, &temp);
+  if (!IS_CPU_TIC3X (temp) && !IS_CPU_TIC4X (temp))
+    as_bad ("This assembler does not support processor generation %ld",
+           (long) temp);
+
+  if (tic4x_cpu && temp != (offsetT) tic4x_cpu)
+    as_warn ("Changing processor generation on fly not supported...");
+  tic4x_cpu = temp;
   demand_empty_rest_of_line ();
 }
 
 static void 
-c4x_pseudo_ignore (int x)
-{
-  /* We could print warning message here...  */
-
-  /* Ignore everything until end of line.  */
-  while (!is_end_of_line[(unsigned char) *input_line_pointer++]);
-}
-
-static void 
-c4x_init_regtable (void)
+tic4x_init_regtable (void)
 {
   unsigned int i;
 
-  for (i = 0; i < c3x_num_registers; i++)
-    c4x_insert_reg (c3x_registers[i].name,
-                   c3x_registers[i].regno);
+  for (i = 0; i < tic3x_num_registers; i++)
+    tic4x_insert_reg (tic3x_registers[i].name,
+                   tic3x_registers[i].regno);
 
-  if (IS_CPU_C4X (c4x_cpu))
+  if (IS_CPU_TIC4X (tic4x_cpu))
     {
-      /* Add additional C4x registers, overriding some C3x ones.  */
-      for (i = 0; i < c4x_num_registers; i++)
-       c4x_insert_reg (c4x_registers[i].name,
-                       c4x_registers[i].regno);
+      /* Add additional Tic4x registers, overriding some C3x ones.  */
+      for (i = 0; i < tic4x_num_registers; i++)
+       tic4x_insert_reg (tic4x_registers[i].name,
+                       tic4x_registers[i].regno);
     }
 }
 
 static void 
-c4x_init_symbols (void)
+tic4x_init_symbols (void)
 {
   /* The TI tools accept case insensitive versions of these symbols,
      we don't !
@@ -1056,33 +1196,35 @@ c4x_init_symbols (void)
 
      Source: TI: TMS320C3x/C4x Assembly Language Tools User's Guide,
      1997, SPRU035C, p. 3-17/3-18.  */
-  c4x_insert_sym (".REGPARM", c4x_reg_args);
-  c4x_insert_sym (".MEMPARM", !c4x_reg_args);  
-  c4x_insert_sym (".BIGMODEL", c4x_big_model);
-  c4x_insert_sym (".C30INTERRUPT", 0);
-  c4x_insert_sym (".TMS320xx", c4x_cpu == 0 ? 40 : c4x_cpu);
-  c4x_insert_sym (".C3X", c4x_cpu == 30 || c4x_cpu == 31 || c4x_cpu == 32);
-  c4x_insert_sym (".C3x", c4x_cpu == 30 || c4x_cpu == 31 || c4x_cpu == 32);
-  c4x_insert_sym (".C4X", c4x_cpu == 0 || c4x_cpu == 40 || c4x_cpu == 44);
-  c4x_insert_sym (".C4x", c4x_cpu == 0 || c4x_cpu == 40 || c4x_cpu == 44);
+  tic4x_insert_sym (".REGPARM", tic4x_reg_args);
+  tic4x_insert_sym (".MEMPARM", !tic4x_reg_args);      
+  tic4x_insert_sym (".BIGMODEL", tic4x_big_model);
+  tic4x_insert_sym (".C30INTERRUPT", 0);
+  tic4x_insert_sym (".TMS320xx", tic4x_cpu == 0 ? 40 : tic4x_cpu);
+  tic4x_insert_sym (".C3X", tic4x_cpu == 30 || tic4x_cpu == 31 || tic4x_cpu == 32 || tic4x_cpu == 33);
+  tic4x_insert_sym (".C3x", tic4x_cpu == 30 || tic4x_cpu == 31 || tic4x_cpu == 32 || tic4x_cpu == 33);
+  tic4x_insert_sym (".C4X", tic4x_cpu == 0 || tic4x_cpu == 40 || tic4x_cpu == 44);
+  tic4x_insert_sym (".C4x", tic4x_cpu == 0 || tic4x_cpu == 40 || tic4x_cpu == 44);
   /* Do we need to have the following symbols also in lower case?  */
-  c4x_insert_sym (".TMS320C30", c4x_cpu == 30 || c4x_cpu == 31 || c4x_cpu == 32);
-  c4x_insert_sym (".tms320C30", c4x_cpu == 30 || c4x_cpu == 31 || c4x_cpu == 32);
-  c4x_insert_sym (".TMS320C31", c4x_cpu == 31);
-  c4x_insert_sym (".tms320C31", c4x_cpu == 31);
-  c4x_insert_sym (".TMS320C32", c4x_cpu == 32);
-  c4x_insert_sym (".tms320C32", c4x_cpu == 32);
-  c4x_insert_sym (".TMS320C40", c4x_cpu == 40 || c4x_cpu == 44 || c4x_cpu == 0);
-  c4x_insert_sym (".tms320C40", c4x_cpu == 40 || c4x_cpu == 44 || c4x_cpu == 0);
-  c4x_insert_sym (".TMS320C44", c4x_cpu == 44);
-  c4x_insert_sym (".tms320C44", c4x_cpu == 44);
-  c4x_insert_sym (".TMX320C40", 0);    /* C40 first pass silicon ?  */
-  c4x_insert_sym (".tmx320C40", 0);
+  tic4x_insert_sym (".TMS320C30", tic4x_cpu == 30 || tic4x_cpu == 31 || tic4x_cpu == 32 || tic4x_cpu == 33);
+  tic4x_insert_sym (".tms320C30", tic4x_cpu == 30 || tic4x_cpu == 31 || tic4x_cpu == 32 || tic4x_cpu == 33);
+  tic4x_insert_sym (".TMS320C31", tic4x_cpu == 31);
+  tic4x_insert_sym (".tms320C31", tic4x_cpu == 31);
+  tic4x_insert_sym (".TMS320C32", tic4x_cpu == 32);
+  tic4x_insert_sym (".tms320C32", tic4x_cpu == 32);
+  tic4x_insert_sym (".TMS320C33", tic4x_cpu == 33);
+  tic4x_insert_sym (".tms320C33", tic4x_cpu == 33);
+  tic4x_insert_sym (".TMS320C40", tic4x_cpu == 40 || tic4x_cpu == 44 || tic4x_cpu == 0);
+  tic4x_insert_sym (".tms320C40", tic4x_cpu == 40 || tic4x_cpu == 44 || tic4x_cpu == 0);
+  tic4x_insert_sym (".TMS320C44", tic4x_cpu == 44);
+  tic4x_insert_sym (".tms320C44", tic4x_cpu == 44);
+  tic4x_insert_sym (".TMX320C40", 0);  /* C40 first pass silicon ?  */
+  tic4x_insert_sym (".tmx320C40", 0);
 }
 
 /* Insert a new instruction template into hash table.  */
 static int 
-c4x_inst_insert (c4x_inst_t *inst)
+tic4x_inst_insert (const tic4x_inst_t *inst)
 {
   static char prev_name[16];
   const char *retval = NULL;
@@ -1091,7 +1233,7 @@ c4x_inst_insert (c4x_inst_t *inst)
   if (!strcmp (inst->name, prev_name) || inst->name[0] == '\0')
     return 1;
 
-  retval = hash_insert (c4x_op_hash, inst->name, (PTR) inst);
+  retval = hash_insert (tic4x_op_hash, inst->name, (void *) inst);
   if (retval != NULL)
     fprintf (stderr, "internal error: can't hash `%s': %s\n",
             inst->name, retval);
@@ -1101,10 +1243,10 @@ c4x_inst_insert (c4x_inst_t *inst)
 }
 
 /* Make a new instruction template.  */
-static c4x_inst_t *
-c4x_inst_make (char *name, unsigned long opcode, char *args)
+static tic4x_inst_t *
+tic4x_inst_make (char *name, unsigned long opcode, char *args)
 {
-  static c4x_inst_t *insts = NULL;
+  static tic4x_inst_t *insts = NULL;
   static char *names = NULL;
   static int index = 0;
 
@@ -1113,8 +1255,8 @@ c4x_inst_make (char *name, unsigned long opcode, char *args)
       /* Allocate memory to store name strings.  */
       names = (char *) xmalloc (sizeof (char) * 8192);
       /* Allocate memory for additional insts.  */
-      insts = (c4x_inst_t *)
-       xmalloc (sizeof (c4x_inst_t) * 1024);
+      insts = (tic4x_inst_t *)
+       xmalloc (sizeof (tic4x_inst_t) * 1024);
     }
   insts[index].name = names;
   insts[index].opcode = opcode;
@@ -1132,7 +1274,7 @@ c4x_inst_make (char *name, unsigned long opcode, char *args)
 
 /* Add instruction template, creating dynamic templates as required.  */
 static int 
-c4x_inst_add (c4x_inst_t *insts)
+tic4x_inst_add (const tic4x_inst_t *insts)
 {
   char *s = insts->name;
   char *d;
@@ -1142,6 +1284,11 @@ c4x_inst_add (c4x_inst_t *insts)
 
   d = name;
 
+  /* We do not care about INSNs that is not a part of our
+     oplevel setting */
+  if (!insts->oplevel & tic4x_oplevel)
+    return ok;
+
   while (1)
     {
       switch (*s)
@@ -1149,11 +1296,11 @@ c4x_inst_add (c4x_inst_t *insts)
        case 'B':
        case 'C':
          /* Dynamically create all the conditional insts.  */
-         for (i = 0; i < num_conds; i++)
+         for (i = 0; i < tic4x_num_conds; i++)
            {
-             c4x_inst_t *inst;
+             tic4x_inst_t *inst;
              int k = 0;
-             char *c = c4x_conds[i].name;
+             char *c = tic4x_conds[i].name;
              char *e = d;
 
              while (*c)
@@ -1164,17 +1311,17 @@ c4x_inst_add (c4x_inst_t *insts)
              *e = '\0';
 
              /* If instruction found then have already processed it.  */
-             if (hash_find (c4x_op_hash, name))
+             if (hash_find (tic4x_op_hash, name))
                return 1;
 
              do
                {
-                 inst = c4x_inst_make (name, insts[k].opcode +
-                                       (c4x_conds[i].cond <<
+                 inst = tic4x_inst_make (name, insts[k].opcode +
+                                       (tic4x_conds[i].cond <<
                                         (*s == 'B' ? 16 : 23)),
                                        insts[k].args);
                  if (k == 0)   /* Save strcmp() with following func.  */
-                   ok &= c4x_inst_insert (inst);
+                   ok &= tic4x_inst_insert (inst);
                  k++;
                }
              while (!strcmp (insts->name,
@@ -1184,7 +1331,7 @@ c4x_inst_add (c4x_inst_t *insts)
          break;
 
        case '\0':
-         return c4x_inst_insert (insts);
+         return tic4x_inst_insert (insts);
          break;
 
        default:
@@ -1203,45 +1350,67 @@ md_begin (void)
   int ok = 1;
   unsigned int i;
 
+  /* Setup the proper opcode level according to the
+     commandline parameters */
+  tic4x_oplevel = OP_C3X;
+
+  if ( IS_CPU_TIC4X(tic4x_cpu) )
+    tic4x_oplevel |= OP_C4X;
+
+  if ( (   tic4x_cpu == 31 && tic4x_revision >= 6)
+       || (tic4x_cpu == 32 && tic4x_revision >= 2)
+       || (tic4x_cpu == 33)
+       || tic4x_enhanced )
+    tic4x_oplevel |= OP_ENH;
+
+  if ( (   tic4x_cpu == 30 && tic4x_revision >= 7)
+       || (tic4x_cpu == 31 && tic4x_revision >= 5)
+       || (tic4x_cpu == 32)
+       || tic4x_lowpower )
+    tic4x_oplevel |= OP_LPWR;
+
+  if ( (   tic4x_cpu == 30 && tic4x_revision >= 7)
+       || (tic4x_cpu == 31 && tic4x_revision >= 5)
+       || (tic4x_cpu == 32)
+       || (tic4x_cpu == 33)
+       || (tic4x_cpu == 40 && tic4x_revision >= 5)
+       || (tic4x_cpu == 44)
+       || tic4x_idle2 )
+    tic4x_oplevel |= OP_IDLE2;
+
   /* Create hash table for mnemonics.  */
-  c4x_op_hash = hash_new ();
+  tic4x_op_hash = hash_new ();
 
   /* Create hash table for asg pseudo.  */
-  c4x_asg_hash = hash_new ();
+  tic4x_asg_hash = hash_new ();
 
   /* Add mnemonics to hash table, expanding conditional mnemonics on fly.  */
-  for (i = 0; i < c3x_num_insts; i++)
-    ok &= c4x_inst_add ((void *) &c3x_insts[i]);
-
-  if (IS_CPU_C4X (c4x_cpu))
-    {
-      for (i = 0; i < c4x_num_insts; i++)
-       ok &= c4x_inst_add ((void *) &c4x_insts[i]);
-    }
+  for (i = 0; i < tic4x_num_insts; i++)
+    ok &= tic4x_inst_add (tic4x_insts + i);
 
   /* Create dummy inst to avoid errors accessing end of table.  */
-  c4x_inst_make ("", 0, "");
+  tic4x_inst_make ("", 0, "");
 
   if (!ok)
     as_fatal ("Broken assembler.  No assembly attempted.");
 
   /* Add registers to symbol table.  */
-  c4x_init_regtable ();
+  tic4x_init_regtable ();
 
   /* Add predefined symbols to symbol table.  */
-  c4x_init_symbols ();
+  tic4x_init_symbols ();
 }
 
 void 
-c4x_end (void)
+tic4x_end (void)
 {
   bfd_set_arch_mach (stdoutput, bfd_arch_tic4x, 
-                    IS_CPU_C4X (c4x_cpu) ? bfd_mach_c4x : bfd_mach_c3x);
+                    IS_CPU_TIC4X (tic4x_cpu) ? bfd_mach_tic4x : bfd_mach_tic3x);
 }
 
 static int 
-c4x_indirect_parse (c4x_operand_t *operand,
-                   const c4x_indirect_t *indirect)
+tic4x_indirect_parse (tic4x_operand_t *operand,
+                     const tic4x_indirect_t *indirect)
 {
   char *n = indirect->name;
   char *s = input_line_pointer;
@@ -1256,11 +1425,11 @@ c4x_indirect_parse (c4x_operand_t *operand,
        {
        case 'a':               /* Need to match aux register.  */
          b = name;
-#ifdef C4X_ALT_SYNTAX
+#ifdef TIC4X_ALT_SYNTAX
          if (*s == '%')
            s++;
 #endif
-         while (isalnum (*s))
+         while (ISALNUM (*s))
            *b++ = *s++;
          *b++ = '\0';
          if (!(symbolP = symbol_find (name)))
@@ -1277,11 +1446,11 @@ c4x_indirect_parse (c4x_operand_t *operand,
          return -1;
 
        case 'd':               /* Need to match constant for disp.  */
-#ifdef C4X_ALT_SYNTAX
+#ifdef TIC4X_ALT_SYNTAX
          if (*s == '%')        /* expr() will die if we don't skip this.  */
            s++;
 #endif
-         s = c4x_expression (s, &operand->expr);
+         s = tic4x_expression (s, &operand->expr);
          if (operand->expr.X_op != O_constant)
            return 0;
          operand->disp = operand->expr.X_add_number;
@@ -1295,11 +1464,11 @@ c4x_indirect_parse (c4x_operand_t *operand,
 
        case 'y':               /* Need to match IR0.  */
        case 'z':               /* Need to match IR1.  */
-#ifdef C4X_ALT_SYNTAX
+#ifdef TIC4X_ALT_SYNTAX
          if (*s == '%')
            s++;
 #endif
-         s = c4x_expression (s, &operand->expr);
+         s = tic4x_expression (s, &operand->expr);
          if (operand->expr.X_op != O_register)
            return 0;
          if (operand->expr.X_add_number != REG_IR0
@@ -1327,7 +1496,7 @@ c4x_indirect_parse (c4x_operand_t *operand,
          break;
 
        default:
-         if (tolower (*s) != *n)
+         if (TOLOWER (*s) != *n)
            return 0;
          s++;
        }
@@ -1338,8 +1507,8 @@ c4x_indirect_parse (c4x_operand_t *operand,
   return 1;
 }
 
-char *
-c4x_operand_parse (char *s, c4x_operand_t *operand)
+static char *
+tic4x_operand_parse (char *s, tic4x_operand_t *operand)
 {
   unsigned int i;
   char c;
@@ -1356,7 +1525,7 @@ c4x_operand_parse (char *s, c4x_operand_t *operand)
   str = input_line_pointer;
   c = get_symbol_end ();       /* Get terminator.  */
   new = input_line_pointer;
-  if (strlen (str) && (entry = hash_find (c4x_asg_hash, str)) != NULL)
+  if (strlen (str) && (entry = hash_find (tic4x_asg_hash, str)) != NULL)
     {
       *input_line_pointer = c;
       input_line_pointer = (char *) entry;
@@ -1370,9 +1539,9 @@ c4x_operand_parse (char *s, c4x_operand_t *operand)
   operand->mode = M_UNKNOWN;
   switch (*input_line_pointer)
     {
-#ifdef C4X_ALT_SYNTAX
+#ifdef TIC4X_ALT_SYNTAX
     case '%':
-      input_line_pointer = c4x_expression (++input_line_pointer, exp);
+      input_line_pointer = tic4x_expression (++input_line_pointer, exp);
       if (exp->X_op != O_register)
        as_bad ("Expecting a register name");
       operand->mode = M_REGISTER;
@@ -1380,7 +1549,7 @@ c4x_operand_parse (char *s, c4x_operand_t *operand)
 
     case '^':
       /* Denotes high 16 bits.  */
-      input_line_pointer = c4x_expression (++input_line_pointer, exp);
+      input_line_pointer = tic4x_expression (++input_line_pointer, exp);
       if (exp->X_op == O_constant)
        operand->mode = M_IMMED;
       else if (exp->X_op == O_big)
@@ -1389,7 +1558,7 @@ c4x_operand_parse (char *s, c4x_operand_t *operand)
            as_bad ("Number too large");        /* bignum required */
          else
            {
-             c4x_gen_to_words (generic_floating_point_number,
+             tic4x_gen_to_words (generic_floating_point_number,
                                operand->fwords, S_PRECISION);
              operand->mode = M_IMMED_F;
            }
@@ -1403,7 +1572,7 @@ c4x_operand_parse (char *s, c4x_operand_t *operand)
        }
 
     case '#':
-      input_line_pointer = c4x_expression (++input_line_pointer, exp);
+      input_line_pointer = tic4x_expression (++input_line_pointer, exp);
       if (exp->X_op == O_constant)
        operand->mode = M_IMMED;
       else if (exp->X_op == O_big)
@@ -1412,7 +1581,7 @@ c4x_operand_parse (char *s, c4x_operand_t *operand)
            as_bad ("Number too large");        /* bignum required.  */
          else
            {
-             c4x_gen_to_words (generic_floating_point_number,
+             tic4x_gen_to_words (generic_floating_point_number,
                                operand->fwords, S_PRECISION);
              operand->mode = M_IMMED_F;
            }
@@ -1431,7 +1600,7 @@ c4x_operand_parse (char *s, c4x_operand_t *operand)
     case '\\':
 #endif
     case '@':
-      input_line_pointer = c4x_expression (++input_line_pointer, exp);
+      input_line_pointer = tic4x_expression (++input_line_pointer, exp);
       if (exp->X_op != O_constant && exp->X_op != O_symbol)
        as_bad ("Bad direct addressing construct %s", s);
       if (exp->X_op == O_constant)
@@ -1445,16 +1614,16 @@ c4x_operand_parse (char *s, c4x_operand_t *operand)
 
     case '*':
       ret = -1;
-      for (i = 0; i < num_indirects; i++)
-       if ((ret = c4x_indirect_parse (operand, &c4x_indirects[i])))
+      for (i = 0; i < tic4x_num_indirects; i++)
+       if ((ret = tic4x_indirect_parse (operand, &tic4x_indirects[i])))
          break;
       if (ret < 0)
        break;
-      if (i < num_indirects)
+      if (i < tic4x_num_indirects)
        {
          operand->mode = M_INDIRECT;
          /* Indirect addressing mode number.  */
-         operand->expr.X_add_number = c4x_indirects[i].modn;
+         operand->expr.X_add_number = tic4x_indirects[i].modn;
          /* Convert *+ARn(0) to *ARn etc.  Maybe we should
             squeal about silly ones?  */
          if (operand->expr.X_add_number < 0x08 && !operand->disp)
@@ -1467,7 +1636,7 @@ c4x_operand_parse (char *s, c4x_operand_t *operand)
     default:
       operand->mode = M_IMMED; /* Assume immediate.  */
       str = input_line_pointer;
-      input_line_pointer = c4x_expression (input_line_pointer, exp);
+      input_line_pointer = tic4x_expression (input_line_pointer, exp);
       if (exp->X_op == O_register)
        {
          know (exp->X_add_symbol == 0);
@@ -1481,13 +1650,13 @@ c4x_operand_parse (char *s, c4x_operand_t *operand)
            as_bad ("Number too large");        /* bignum required.  */
          else
            {
-             c4x_gen_to_words (generic_floating_point_number,
+             tic4x_gen_to_words (generic_floating_point_number,
                                operand->fwords, S_PRECISION);
              operand->mode = M_IMMED_F;
            }
          break;
        }
-#ifdef C4X_ALT_SYNTAX
+#ifdef TIC4X_ALT_SYNTAX
       /* Allow ldi foo, ar0 to be equivalent to ldi @foo, ar0.  */
       else if (exp->X_op == O_symbol)
        {
@@ -1503,12 +1672,12 @@ c4x_operand_parse (char *s, c4x_operand_t *operand)
 }
 
 static int 
-c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
+tic4x_operands_match (tic4x_inst_t *inst, tic4x_insn_t *insn, int check)
 {
   const char *args = inst->args;
   unsigned long opcode = inst->opcode;
   int num_operands = insn->num_operands;
-  c4x_operand_t *operand = insn->operands;
+  tic4x_operand_t *operand = insn->operands;
   expressionS *exp = &operand->expr;
   int ret = 1;
   int reg;
@@ -1549,9 +1718,20 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
             use an immediate mode form of ldiu or ldpk instruction.  */
          if (exp->X_op == O_constant)
            {
-             /* Maybe for C3x we should check for 8 bit number.  */
-             INSERTS (opcode, exp->X_add_number, 15, 0);
-             continue;
+              if( ( IS_CPU_TIC4X (tic4x_cpu) && exp->X_add_number <= 65535 )
+                  || ( IS_CPU_TIC3X (tic4x_cpu) && exp->X_add_number <= 255 ) )
+                {
+                  INSERTS (opcode, exp->X_add_number, 15, 0);
+                  continue;
+                }
+              else
+                {
+                 if (!check)
+                    as_bad ("Immediate value of %ld is too large for ldf",
+                            (long) exp->X_add_number);
+                 ret = -1;
+                 continue;
+                }
            }
          else if (exp->X_op == O_symbol)
            {
@@ -1565,10 +1745,10 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
          if (operand->mode != M_DIRECT)
            break;
          if (exp->X_op == O_constant)
-           {
-             /* Store only the 16 LSBs of the number.  */
-             INSERTS (opcode, exp->X_add_number, 15, 0);
-             continue;
+            {
+              /* Store only the 16 LSBs of the number.  */
+              INSERTS (opcode, exp->X_add_number, 15, 0);
+              continue;
            }
          else if (exp->X_op == O_symbol)
            {
@@ -1586,7 +1766,8 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
            INSERTU (opcode, reg - REG_AR0, 24, 22);
          else
            {
-             as_bad ("Destination register must be ARn");
+              if (!check)
+                as_bad ("Destination register must be ARn");
              ret = -1;
            }
          continue;
@@ -1604,13 +1785,14 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
                }
              else
                {
-                 as_bad ("Immediate value of %ld is too large",
-                         (long) exp->X_add_number);
+                 if (!check)
+                    as_bad ("Immediate value of %ld is too large",
+                            (long) exp->X_add_number);
                  ret = -1;
                  continue;
                }
            }
-         if (IS_CPU_C4X (c4x_cpu))
+         if (IS_CPU_TIC4X (tic4x_cpu))
            {
              insn->reloc = BFD_RELOC_24_PCREL;
              insn->pcrel = 1;
@@ -1624,15 +1806,17 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
          continue;
 
        case 'C':
-         if (!IS_CPU_C4X (c4x_cpu))
+         if (!IS_CPU_TIC4X (tic4x_cpu))
            break;
          if (operand->mode != M_INDIRECT)
            break;
+         /* Require either *+ARn(disp) or *ARn.  */
          if (operand->expr.X_add_number != 0
              && operand->expr.X_add_number != 0x18)
            {
-             as_bad ("Invalid indirect addressing mode");
-             ret = -1;
+              if (!check)
+                as_bad ("Invalid indirect addressing mode");
+              ret = -1;
              continue;
            }
          INSERTU (opcode, operand->aregno - REG_AR0, 2, 0);
@@ -1645,6 +1829,21 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
          INSERTU (opcode, exp->X_add_number, 7, 0);
          continue;
 
+        case 'e':
+          if (!(operand->mode == M_REGISTER))
+            break;
+         reg = exp->X_add_number;
+         if ( (reg >= REG_R0 && reg <= REG_R7) 
+               || (IS_CPU_TIC4X (tic4x_cpu) && reg >= REG_R8 && reg <= REG_R11) )
+           INSERTU (opcode, reg, 7, 0);
+         else
+           {
+              if (!check)
+                as_bad ("Register must be Rn");
+             ret = -1;
+           }
+          continue;
+
        case 'F':
          if (operand->mode != M_IMMED_F
              && !(operand->mode == M_IMMED && exp->X_op == O_constant))
@@ -1658,7 +1857,7 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
 
              /* Create floating point number string.  */
              sprintf (string, "%d.0", (int) exp->X_add_number);
-             c4x_atof (string, 's', operand->fwords);
+             tic4x_atof (string, 's', operand->fwords);
            }
 
          INSERTU (opcode, operand->fwords[0], 15, 0);
@@ -1670,6 +1869,21 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
          INSERTU (opcode, exp->X_add_number, 15, 8);
          continue;
 
+        case 'g':
+         if (operand->mode != M_REGISTER)
+           break;
+         reg = exp->X_add_number;
+         if ( (reg >= REG_R0 && reg <= REG_R7) 
+               || (IS_CPU_TIC4X (tic4x_cpu) && reg >= REG_R8 && reg <= REG_R11) )
+           INSERTU (opcode, reg, 15, 8);
+         else
+           {
+              if (!check)
+                as_bad ("Register must be Rn");
+             ret = -1;
+           }
+          continue;
+
        case 'H':
          if (operand->mode != M_REGISTER)
            break;
@@ -1678,20 +1892,33 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
            INSERTU (opcode, reg - REG_R0, 18, 16);
          else
            {
-             as_bad ("Register must be R0--R7");
+              if (!check)
+                as_bad ("Register must be R0--R7");
              ret = -1;
            }
          continue;
 
+        case 'i':
+          if ( operand->mode == M_REGISTER
+               && tic4x_oplevel & OP_ENH )
+            {
+              reg = exp->X_add_number;
+              INSERTU (opcode, reg, 4, 0);
+              INSERTU (opcode, 7, 7, 5);
+              continue;
+            }
+          /* Fallthrough */
+
        case 'I':
          if (operand->mode != M_INDIRECT)
            break;
          if (operand->disp != 0 && operand->disp != 1)
            {
-             if (IS_CPU_C4X (c4x_cpu))
+             if (IS_CPU_TIC4X (tic4x_cpu))
                break;
-             as_bad ("Invalid indirect addressing mode displacement %d",
-                     operand->disp);
+              if (!check)
+                as_bad ("Invalid indirect addressing mode displacement %d",
+                        operand->disp);
              ret = -1;
              continue;
            }
@@ -1699,15 +1926,27 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
          INSERTU (opcode, operand->expr.X_add_number, 7, 3);
          continue;
 
+        case 'j':
+          if ( operand->mode == M_REGISTER
+               && tic4x_oplevel & OP_ENH )
+            {
+              reg = exp->X_add_number;
+              INSERTU (opcode, reg, 12, 8);
+              INSERTU (opcode, 7, 15, 13);
+              continue;
+            }
+          /* Fallthrough */
+
        case 'J':
          if (operand->mode != M_INDIRECT)
            break;
          if (operand->disp != 0 && operand->disp != 1)
            {
-             if (IS_CPU_C4X (c4x_cpu))
+             if (IS_CPU_TIC4X (tic4x_cpu))
                break;
-             as_bad ("Invalid indirect addressing mode displacement %d",
-                     operand->disp);
+              if (!check)
+                as_bad ("Invalid indirect addressing mode displacement %d",
+                        operand->disp);
              ret = -1;
              continue;
            }
@@ -1723,7 +1962,8 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
            INSERTU (opcode, reg - REG_R0, 21, 19);
          else
            {
-             as_bad ("Register must be R0--R7");
+              if (!check)
+                as_bad ("Register must be R0--R7");
              ret = -1;
            }
          continue;
@@ -1736,7 +1976,8 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
            INSERTU (opcode, reg - REG_R0, 24, 22);
          else
            {
-             as_bad ("Register must be R0--R7");
+              if (!check)
+                as_bad ("Register must be R0--R7");
              ret = -1;
            }
          continue;
@@ -1749,7 +1990,8 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
            INSERTU (opcode, reg - REG_R2, 22, 22);
          else
            {
-             as_bad ("Destination register must be R2 or R3");
+              if (!check)
+                as_bad ("Destination register must be R2 or R3");
              ret = -1;
            }
          continue;
@@ -1762,13 +2004,14 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
            INSERTU (opcode, reg - REG_R0, 23, 23);
          else
            {
-             as_bad ("Destination register must be R0 or R1");
+              if (!check)
+                as_bad ("Destination register must be R0 or R1");
              ret = -1;
            }
          continue;
 
        case 'O':
-         if (!IS_CPU_C4X (c4x_cpu))
+         if (!IS_CPU_TIC4X (tic4x_cpu))
            break;
          if (operand->mode != M_INDIRECT)
            break;
@@ -1776,7 +2019,8 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
          if (operand->expr.X_add_number != 0
              && operand->expr.X_add_number != 0x18)
            {
-             as_bad ("Invalid indirect addressing mode");
+              if (!check)
+                as_bad ("Invalid indirect addressing mode");
              ret = -1;
              continue;
            }
@@ -1797,8 +2041,9 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
                }
              else
                {
-                 as_bad ("Displacement value of %ld is too large",
-                         (long) exp->X_add_number);
+                  if (!check)
+                    as_bad ("Displacement value of %ld is too large",
+                            (long) exp->X_add_number);
                  ret = -1;
                  continue;
                }
@@ -1815,6 +2060,21 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
          INSERTU (opcode, reg, 15, 0);
          continue;
 
+        case 'q':
+         if (operand->mode != M_REGISTER)
+           break;
+         reg = exp->X_add_number;
+         if ( (reg >= REG_R0 && reg <= REG_R7) 
+               || (IS_CPU_TIC4X (tic4x_cpu) && reg >= REG_R8 && reg <= REG_R11) )
+           INSERTU (opcode, reg, 15, 0);
+         else
+           {
+              if (!check)
+                as_bad ("Register must be Rn");
+             ret = -1;
+           }
+          continue;
+
        case 'R':
          if (operand->mode != M_REGISTER)
            break;
@@ -1822,12 +2082,28 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
          INSERTU (opcode, reg, 20, 16);
          continue;
 
+        case 'r':
+         if (operand->mode != M_REGISTER)
+           break;
+         reg = exp->X_add_number;
+         if ( (reg >= REG_R0 && reg <= REG_R7) 
+               || (IS_CPU_TIC4X (tic4x_cpu) && reg >= REG_R8 && reg <= REG_R11) )
+           INSERTU (opcode, reg, 20, 16);
+         else
+           {
+              if (!check)
+                as_bad ("Register must be Rn");
+             ret = -1;
+           }
+          continue;
+
        case 'S':               /* Short immediate int.  */
          if (operand->mode != M_IMMED && operand->mode != M_HI)
            break;
          if (exp->X_op == O_big)
            {
-             as_bad ("Floating point number not valid in expression");
+              if (!check)
+                as_bad ("Floating point number not valid in expression");
              ret = -1;
              continue;
            }
@@ -1840,8 +2116,9 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
                }
              else
                {
-                 as_bad ("Signed immediate value %ld too large",
-                         (long) exp->X_add_number);
+                 if (!check)
+                    as_bad ("Signed immediate value %ld too large",
+                            (long) exp->X_add_number);
                  ret = -1;
                  continue;
                }
@@ -1867,8 +2144,8 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
          insn->exp = *exp;
          continue;
 
-       case 'T':               /* 5-bit immediate value for c4x stik.  */
-         if (!IS_CPU_C4X (c4x_cpu))
+       case 'T':               /* 5-bit immediate value for tic4x stik.  */
+         if (!IS_CPU_TIC4X (tic4x_cpu))
            break;
          if (operand->mode != M_IMMED)
            break;
@@ -1881,8 +2158,9 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
                }
              else
                {
-                 as_bad ("Immediate value of %ld is too large",
-                         (long) exp->X_add_number);
+                  if (!check)
+                    as_bad ("Immediate value of %ld is too large",
+                            (long) exp->X_add_number);
                  ret = -1;
                  continue;
                }
@@ -1901,8 +2179,9 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
                }
              else
                {
-                 as_bad ("Unsigned immediate value %ld too large",
-                         (long) exp->X_add_number);
+                  if (!check)
+                    as_bad ("Unsigned immediate value %ld too large",
+                            (long) exp->X_add_number);
                  ret = -1;
                  continue;
                }
@@ -1926,20 +2205,21 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
            break;
          if (exp->X_op == O_constant)
            {
-             if (exp->X_add_number < 512 && IS_CPU_C4X (c4x_cpu))
+             if (exp->X_add_number < 512 && IS_CPU_TIC4X (tic4x_cpu))
                {
                  INSERTU (opcode, exp->X_add_number, 8, 0);
                  continue;
                }
-             else if (exp->X_add_number < 32 && IS_CPU_C3X (c4x_cpu))
+             else if (exp->X_add_number < 32 && IS_CPU_TIC3X (tic4x_cpu))
                {
                  INSERTU (opcode, exp->X_add_number | 0x20, 4, 0);
                  continue;
                }
              else
                {
-                 as_bad ("Immediate value of %ld is too large",
-                         (long) exp->X_add_number);
+                  if (!check)
+                    as_bad ("Immediate value of %ld is too large",
+                            (long) exp->X_add_number);
                  ret = -1;
                  continue;
                }
@@ -1947,13 +2227,14 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
          break;                /* No relocations allowed.  */
 
        case 'W':               /* Short immediate int (0--7).  */
-         if (!IS_CPU_C4X (c4x_cpu))
+         if (!IS_CPU_TIC4X (tic4x_cpu))
            break;
          if (operand->mode != M_IMMED)
            break;
          if (exp->X_op == O_big)
            {
-             as_bad ("Floating point number not valid in expression");
+              if (!check)
+                as_bad ("Floating point number not valid in expression");
              ret = -1;
              continue;
            }
@@ -1966,8 +2247,9 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
                }
              else
                {
-                 as_bad ("Immediate value %ld too large",
-                         (long) exp->X_add_number);
+                  if (!check)
+                    as_bad ("Immediate value %ld too large",
+                            (long) exp->X_add_number);
                  ret = -1;
                  continue;
                }
@@ -1976,7 +2258,7 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
          insn->exp = *exp;
          continue;
 
-       case 'X':               /* Expansion register for c4x.  */
+       case 'X':               /* Expansion register for tic4x.  */
          if (operand->mode != M_REGISTER)
            break;
          reg = exp->X_add_number;
@@ -1984,12 +2266,13 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
            INSERTU (opcode, reg - REG_IVTP, 4, 0);
          else
            {
-             as_bad ("Register must be ivtp or tvtp");
+              if (!check)
+                as_bad ("Register must be ivtp or tvtp");
              ret = -1;
            }
          continue;
 
-       case 'Y':               /* Address register for c4x lda.  */
+       case 'Y':               /* Address register for tic4x lda.  */
          if (operand->mode != M_REGISTER)
            break;
          reg = exp->X_add_number;
@@ -1997,12 +2280,13 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
            INSERTU (opcode, reg, 20, 16);
          else
            {
-             as_bad ("Register must be address register");
+              if (!check)
+                as_bad ("Register must be address register");
              ret = -1;
            }
          continue;
 
-       case 'Z':               /* Expansion register for c4x.  */
+       case 'Z':               /* Expansion register for tic4x.  */
          if (operand->mode != M_REGISTER)
            break;
          reg = exp->X_add_number;
@@ -2010,7 +2294,8 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
            INSERTU (opcode, reg - REG_IVTP, 20, 16);
          else
            {
-             as_bad ("Register must be ivtp or tvtp");
+              if (!check)
+                as_bad ("Register must be ivtp or tvtp");
              ret = -1;
            }
          continue;
@@ -2057,8 +2342,39 @@ c4x_operands_match (c4x_inst_t *inst, c4x_insn_t *insn)
     }
 }
 
-void 
-c4x_insn_output (c4x_insn_t *insn)
+static void
+tic4x_insn_check (tic4x_insn_t *insn)
+{
+  
+  if (!strcmp(insn->name, "lda"))
+    {
+      if (insn->num_operands < 2 || insn->num_operands > 2)
+        as_fatal ("Illegal internal LDA insn definition");
+
+      if ( insn->operands[0].mode == M_REGISTER
+           && insn->operands[1].mode == M_REGISTER
+           && insn->operands[0].expr.X_add_number == insn->operands[1].expr.X_add_number )
+        as_bad ("Source and destination register should not be equal");
+    }
+  else if( !strcmp(insn->name, "ldi_ldi")
+           || !strcmp(insn->name, "ldi1_ldi2")
+           || !strcmp(insn->name, "ldi2_ldi1")
+           || !strcmp(insn->name, "ldf_ldf")
+           || !strcmp(insn->name, "ldf1_ldf2")
+           || !strcmp(insn->name, "ldf2_ldf1") )
+    {
+      if ( insn->num_operands < 4 && insn->num_operands > 5 )
+        as_fatal ("Illegal internal %s insn definition", insn->name);
+      
+      if ( insn->operands[1].mode == M_REGISTER
+           && insn->operands[insn->num_operands-1].mode == M_REGISTER
+           && insn->operands[1].expr.X_add_number == insn->operands[insn->num_operands-1].expr.X_add_number )
+        as_warn ("Equal parallell destination registers, one result will be discarded");
+    }
+}
+
+static void 
+tic4x_insn_output (tic4x_insn_t *insn)
 {
   char *dst;
 
@@ -2082,17 +2398,17 @@ c4x_insn_output (c4x_insn_t *insn)
 }
 
 /* Parse the operands.  */
-int 
-c4x_operands_parse (char *s, c4x_operand_t *operands, int num_operands)
+static int 
+tic4x_operands_parse (char *s, tic4x_operand_t *operands, int num_operands)
 {
   if (!*s)
     return num_operands;
 
   do
-    s = c4x_operand_parse (s, &operands[num_operands++]);
-  while (num_operands < C4X_OPERANDS_MAX && *s++ == ',');
+    s = tic4x_operand_parse (s, &operands[num_operands++]);
+  while (num_operands < TIC4X_OPERANDS_MAX && *s++ == ',');
 
-  if (num_operands > C4X_OPERANDS_MAX)
+  if (num_operands > TIC4X_OPERANDS_MAX)
     {
       as_bad ("Too many operands scanned");
       return -1;
@@ -2110,32 +2426,50 @@ md_assemble (char *str)
   char *s;
   int i;
   int parsed = 0;
-  c4x_inst_t *inst;            /* Instruction template.  */
+  tic4x_inst_t *inst;          /* Instruction template.  */
+  tic4x_inst_t *first_inst;
 
+  /* Scan for parallel operators */
+  if (str)
+    {
+      s = str;
+      while (*s && *s != '|')
+        s++;
+      
+      if (*s && s[1]=='|')
+        {
+          if(insn->parallel)
+            {
+              as_bad ("Parallel opcode cannot contain more than two instructions");
+              insn->parallel = 0;
+              insn->in_use = 0;
+              return;
+            }
+          
+          /* Lets take care of the first part of the parallel insn */
+          *s++ = 0;
+          md_assemble(str);
+          insn->parallel = 1;
+          str = ++s;
+          /* .. and let the second run though here */
+        }
+    }
+  
   if (str && insn->parallel)
     {
-      int star;
-
       /* Find mnemonic (second part of parallel instruction).  */
       s = str;
       /* Skip past instruction mnemonic.  */
-      while (*s && *s != ' ' && *s != '*')
+      while (*s && *s != ' ')
        s++;
-      star = *s == '*';
       if (*s)                  /* Null terminate for hash_find.  */
        *s++ = '\0';            /* and skip past null.  */
       strcat (insn->name, "_");
-      strncat (insn->name, str, C4X_NAME_MAX - strlen (insn->name));
-
-      /* Kludge to overcome problems with scrubber removing
-         space between mnemonic and indirect operand (starting with *)
-         on second line of parallel instruction.  */
-      if (star)
-       *--s = '*';
+      strncat (insn->name, str, TIC4X_NAME_MAX - strlen (insn->name));
 
       insn->operands[insn->num_operands++].mode = M_PARALLEL;
 
-      if ((i = c4x_operands_parse
+      if ((i = tic4x_operands_parse
           (s, insn->operands, insn->num_operands)) < 0)
        {
          insn->parallel = 0;
@@ -2148,8 +2482,8 @@ md_assemble (char *str)
 
   if (insn->in_use)
     {
-      if ((insn->inst = (struct c4x_inst *)
-          hash_find (c4x_op_hash, insn->name)) == NULL)
+      if ((insn->inst = (struct tic4x_inst *)
+          hash_find (tic4x_op_hash, insn->name)) == NULL)
        {
          as_bad ("Unknown opcode `%s'.", insn->name);
          insn->parallel = 0;
@@ -2157,23 +2491,30 @@ md_assemble (char *str)
          return;
        }
 
-      /* FIXME:  The list of templates should be scanned
-         for the candidates with the desired number of operands.
-         We shouldn't issue error messages until we have
-         whittled the list of candidate templates to the most
-         likely one...  We could cache a parsed form of the templates
-         to reduce the time required to match a template.  */
-
       inst = insn->inst;
-
+      first_inst = NULL;
       do
-       ok = c4x_operands_match (inst, insn);
-      while (!ok && !strcmp (inst->name, inst[1].name) && inst++);
+        {
+          ok = tic4x_operands_match (inst, insn, 1);
+          if (ok < 0)
+            {
+              if (!first_inst)
+                first_inst = inst;
+              ok = 0;
+            }
+      } while (!ok && !strcmp (inst->name, inst[1].name) && inst++);
 
       if (ok > 0)
-       c4x_insn_output (insn);
+        {
+          tic4x_insn_check (insn);
+          tic4x_insn_output (insn);
+        }
       else if (!ok)
-       as_bad ("Invalid operands for %s", insn->name);
+        {
+          if (first_inst)
+            tic4x_operands_match (first_inst, insn, 0);
+          as_bad ("Invalid operands for %s", insn->name);
+        }
       else
        as_bad ("Invalid instruction %s", insn->name);
     }
@@ -2186,11 +2527,11 @@ md_assemble (char *str)
        s++;
       if (*s)                  /* Null terminate for hash_find.  */
        *s++ = '\0';            /* and skip past null.  */
-      strncpy (insn->name, str, C4X_NAME_MAX - 3);
+      strncpy (insn->name, str, TIC4X_NAME_MAX - 3);
 
-      if ((i = c4x_operands_parse (s, insn->operands, 0)) < 0)
+      if ((i = tic4x_operands_parse (s, insn->operands, 0)) < 0)
        {
-         insn->inst = NULL;    /* Flag that error occured.  */
+         insn->inst = NULL;    /* Flag that error occurred.  */
          insn->parallel = 0;
          insn->in_use = 0;
          return;
@@ -2204,7 +2545,7 @@ md_assemble (char *str)
 }
 
 void
-c4x_cleanup (void)
+tic4x_cleanup (void)
 {
   if (insn->in_use)
     md_assemble (NULL);
@@ -2212,7 +2553,7 @@ c4x_cleanup (void)
 
 /* Turn a string in input_line_pointer into a floating point constant
    of type type, and store the appropriate bytes in *litP.  The number
-   of LITTLENUMS emitted is stored in *sizeP.  An error message is
+   of chars emitted is stored in *sizeP.  An error message is
    returned, or NULL on OK.  */
 
 char *
@@ -2222,60 +2563,74 @@ md_atof (int type, char *litP, int *sizeP)
   int ieee;
   LITTLENUM_TYPE words[MAX_LITTLENUMS];
   LITTLENUM_TYPE *wordP;
-  unsigned char *t;
+  char *t;
 
   switch (type)
     {
-    case 's':                  /* .single */
+    case 's':          /* .single  */
     case 'S':
       ieee = 0;
       prec = 1;
       break;
 
-    case 'd':                  /* .double */
+    case 'd':          /* .double  */
     case 'D':
-    case 'f':                  /* .float or .single */
+    case 'f':          /* .float  */
     case 'F':
       ieee = 0;
-      prec = 2;                        /* 1 32-bit word */
+      prec = 2;                /* 1 32-bit word */
       break;
 
-    case 'i':                  /* .ieee */
+    case 'i':          /* .ieee */
+    case 'I':
       prec = 2;
       ieee = 1;
+      type = 'f';  /* Rewrite type to be usable by atof_ieee().  */
       break;
 
-    case 'l':                  /* .ldouble */
-      prec = 4;                        /* 2 32-bit words */
-      ieee = 1;
+    case 'e':          /* .ldouble */
+    case 'E':
+      prec = 4;                /* 2 32-bit words */
+      ieee = 0;
       break;
 
     default:
       *sizeP = 0;
-      return "Bad call to md_atof()";
+      return _("Unrecognized or unsupported floating point constant");
     }
 
   if (ieee)
     t = atof_ieee (input_line_pointer, type, words);
   else
-    t = c4x_atof (input_line_pointer, type, words);
+    t = tic4x_atof (input_line_pointer, type, words);
   if (t)
     input_line_pointer = t;
   *sizeP = prec * sizeof (LITTLENUM_TYPE);
-  t = litP;
+
   /* This loops outputs the LITTLENUMs in REVERSE order; in accord with
      little endian byte order.  */
-  for (wordP = words + prec - 1; prec--;)
+  /* SES: However it is required to put the words (32-bits) out in the
+     correct order, hence we write 2 and 2 littlenums in little endian
+     order, while we keep the original order on successive words.  */
+  for (wordP = words; wordP<(words+prec) ; wordP+=2)
     {
-      md_number_to_chars (litP, (valueT) (*wordP--),
-                         sizeof (LITTLENUM_TYPE));
+      if (wordP < (words + prec - 1)) /* Dump wordP[1] (if we have one).  */
+        {
+          md_number_to_chars (litP, (valueT) (wordP[1]),
+                              sizeof (LITTLENUM_TYPE));
+          litP += sizeof (LITTLENUM_TYPE);
+        }
+
+      /* Dump wordP[0] */
+      md_number_to_chars (litP, (valueT) (wordP[0]),
+                          sizeof (LITTLENUM_TYPE));
       litP += sizeof (LITTLENUM_TYPE);
     }
-  return 0;
+  return NULL;
 }
 
 void 
-md_apply_fix3 (fixS *fixP, valueT *value, segT seg ATTRIBUTE_UNUSED)
+md_apply_fix (fixS *fixP, valueT *value, segT seg ATTRIBUTE_UNUSED)
 {
   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
   valueT val = *value;
@@ -2317,69 +2672,100 @@ md_apply_fix3 (fixS *fixP, valueT *value, segT seg ATTRIBUTE_UNUSED)
   if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0) fixP->fx_done = 1;
 }
 
-/* Should never be called for c4x.  */
+/* Should never be called for tic4x.  */
 void 
-md_convert_frag (bfd *headers, segT sec, fragS *fragP)
+md_convert_frag (bfd *headers ATTRIBUTE_UNUSED,
+                segT sec ATTRIBUTE_UNUSED,
+                fragS *fragP ATTRIBUTE_UNUSED)
 {
   as_fatal ("md_convert_frag");
 }
 
-/* Should never be called for c4x.  */
+/* Should never be called for tic4x.  */
 void
-md_create_short_jump (char *ptr, addressT from_addr, addressT to_addr,
-                     fragS *frag, symbolS *to_symbol)
+md_create_short_jump (char *ptr ATTRIBUTE_UNUSED,
+                     addressT from_addr ATTRIBUTE_UNUSED,
+                     addressT to_addr ATTRIBUTE_UNUSED,
+                     fragS *frag ATTRIBUTE_UNUSED,
+                     symbolS *to_symbol ATTRIBUTE_UNUSED)
 {
   as_fatal ("md_create_short_jmp\n");
 }
 
-/* Should never be called for c4x.  */
+/* Should never be called for tic4x.  */
 void
-md_create_long_jump (char *ptr, addressT from_addr, addressT to_addr,
-                    fragS *frag, symbolS *to_symbol)
+md_create_long_jump (char *ptr ATTRIBUTE_UNUSED,
+                    addressT from_addr ATTRIBUTE_UNUSED,
+                    addressT to_addr ATTRIBUTE_UNUSED,
+                    fragS *frag ATTRIBUTE_UNUSED,
+                    symbolS *to_symbol ATTRIBUTE_UNUSED)
 {
   as_fatal ("md_create_long_jump\n");
 }
 
-/* Should never be called for c4x.  */
+/* Should never be called for tic4x.  */
 int
-md_estimate_size_before_relax (register fragS *fragP, segT segtype)
+md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED,
+                              segT segtype ATTRIBUTE_UNUSED)
 {
   as_fatal ("md_estimate_size_before_relax\n");
   return 0;
 }
 
-CONST char *md_shortopts = "bm:prs";
-struct option md_longopts[] =
-{
-  {NULL, no_argument, NULL, 0}
-};
-
-size_t md_longopts_size = sizeof (md_longopts);
 
 int
 md_parse_option (int c, char *arg)
 {
   switch (c)
     {
-    case 'b':                  /* big model */
-      c4x_big_model = 1;
-      break;
-    case 'm':                  /* -m[c][34]x */
-      if (tolower (*arg) == 'c')
+    case OPTION_CPU:             /* cpu brand */
+      if (TOLOWER (*arg) == 'c')
        arg++;
-      c4x_cpu = atoi (arg);
-      if (!IS_CPU_C3X (c4x_cpu) && !IS_CPU_C4X (c4x_cpu))
-       as_warn ("Unsupported processor generation %d\n", c4x_cpu);
+      tic4x_cpu = atoi (arg);
+      if (!IS_CPU_TIC3X (tic4x_cpu) && !IS_CPU_TIC4X (tic4x_cpu))
+       as_warn ("Unsupported processor generation %d", tic4x_cpu);
+      break;
+
+    case OPTION_REV:             /* cpu revision */
+      tic4x_revision = atoi (arg);
+      break;
+
+    case 'b':
+      as_warn ("Option -b is depreciated, please use -mbig");
+    case OPTION_BIG:             /* big model */
+      tic4x_big_model = 1;
       break;
-    case 'p':                  /* push args */
-      c4x_reg_args = 0;
+
+    case 'p':
+      as_warn ("Option -p is depreciated, please use -mmemparm");
+    case OPTION_MEMPARM:         /* push args */
+      tic4x_reg_args = 0;
       break;
-    case 'r':                  /* register args */
-      c4x_reg_args = 1;
+
+    case 'r':                  
+      as_warn ("Option -r is depreciated, please use -mregparm");
+    case OPTION_REGPARM:        /* register args */
+      tic4x_reg_args = 1;
       break;
-    case 's':                  /* small model */
-      c4x_big_model = 0;
+
+    case 's':
+      as_warn ("Option -s is depreciated, please use -msmall");
+    case OPTION_SMALL:         /* small model */
+      tic4x_big_model = 0;
+      break;
+
+    case OPTION_IDLE2:
+      tic4x_idle2 = 1;
+      break;
+
+    case OPTION_LOWPOWER:
+      tic4x_lowpower = 1;
       break;
+
+    case OPTION_ENHANCED:
+      tic4x_enhanced = 1;
+      break;
+
     default:
       return 0;
     }
@@ -2390,34 +2776,45 @@ md_parse_option (int c, char *arg)
 void
 md_show_usage (FILE *stream)
 {
-  fputs ("\
-C[34]x options:\n\
--m30 | -m31 | -m32 | -m40 | -m44\n\
-                       specify variant of architecture\n\
--b                      big memory model\n\
--p                      pass arguments on stack\n\
--r                      pass arguments in registers (default)\n\
--s                      small memory model (default)\n",
-        stream);
+  fprintf (stream,
+      _("\nTIC4X options:\n"
+       "  -mcpu=CPU  -mCPU        select architecture variant. CPU can be:\n"
+       "                            30 - TMS320C30\n"
+       "                            31 - TMS320C31, TMS320LC31\n"
+       "                            32 - TMS320C32\n"
+        "                            33 - TMS320VC33\n"
+       "                            40 - TMS320C40\n"
+       "                            44 - TMS320C44\n"
+        "  -mrev=REV               set cpu hardware revision (integer numbers).\n"
+        "                          Combinations of -mcpu and -mrev will enable/disable\n"
+        "                          the appropriate options (-midle2, -mlowpower and\n"
+        "                          -menhanced) according to the selected type\n"
+        "  -mbig                   select big memory model\n"
+        "  -msmall                 select small memory model (default)\n"
+        "  -mregparm               select register parameters (default)\n"
+        "  -mmemparm               select memory parameters\n"
+        "  -midle2                 enable IDLE2 support\n"
+        "  -mlowpower              enable LOPOWER and MAXSPEED support\n"
+        "  -menhanced              enable enhanced opcode support\n"));
 }
 
 /* This is called when a line is unrecognized.  This is used to handle
    definitions of TI C3x tools style local labels $n where n is a single
    decimal digit.  */
 int 
-c4x_unrecognized_line (int c)
+tic4x_unrecognized_line (int c)
 {
   int lab;
   char *s;
 
-  if (c != '$' || !isdigit (input_line_pointer[0]))
+  if (c != '$' || ! ISDIGIT (input_line_pointer[0]))
     return 0;
 
   s = input_line_pointer;
 
   /* Let's allow multiple digit local labels.  */
   lab = 0;
-  while (isdigit (*s))
+  while (ISDIGIT (*s))
     {
       lab = lab * 10 + *s - '0';
       s++;
@@ -2441,13 +2838,13 @@ symbolS *
 md_undefined_symbol (char *name)
 {
   /* Look for local labels of the form $n.  */
-  if (name[0] == '$' && isdigit (name[1]))
+  if (name[0] == '$' && ISDIGIT (name[1]))
     {
       symbolS *symbolP;
       char *s = name + 1;
       int lab = 0;
 
-      while (isdigit ((unsigned char) *s))
+      while (ISDIGIT ((unsigned char) *s))
        {
          lab = lab * 10 + *s - '0';
          s++;
@@ -2470,19 +2867,19 @@ md_undefined_symbol (char *name)
 
 /* Parse an operand that is machine-specific.  */
 void
-md_operand (expressionS *expressionP)
+md_operand (expressionS *expressionP ATTRIBUTE_UNUSED)
 {
 }
 
 /* Round up a section size to the appropriate boundary---do we need this?  */
 valueT
-md_section_align (segT segment, valueT size)
+md_section_align (segT segment ATTRIBUTE_UNUSED, valueT size)
 {
   return size;                 /* Byte (i.e., 32-bit) alignment is fine?  */
 }
 
 static int 
-c4x_pc_offset (unsigned int op)
+tic4x_pc_offset (unsigned int op)
 {
   /* Determine the PC offset for a C[34]x instruction.
      This could be simplified using some boolean algebra
@@ -2546,33 +2943,52 @@ c4x_pc_offset (unsigned int op)
 long
 md_pcrel_from (fixS *fixP)
 {
-  unsigned char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+  unsigned char *buf;
   unsigned int op;
 
+  buf = (unsigned char *) fixP->fx_frag->fr_literal + fixP->fx_where;
   op = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
 
   return ((fixP->fx_where + fixP->fx_frag->fr_address) >> 2) +
-    c4x_pc_offset (op);
+    tic4x_pc_offset (op);
 }
 
-/* This is probably not necessary, if we have played our cards right,
-   since everything should be already aligned on a 4-byte boundary.  */
+/* Fill the alignment area with NOP's on .text, unless fill-data
+   was specified. */
 int 
-c4x_do_align (int alignment, const char *fill, int len, int max)
+tic4x_do_align (int alignment ATTRIBUTE_UNUSED,
+               const char *fill ATTRIBUTE_UNUSED,
+               int len ATTRIBUTE_UNUSED,
+               int max ATTRIBUTE_UNUSED)
 {
-  char *p;
-
-  p = frag_var (rs_align, 1, 1, (relax_substateT) 0,
-               (symbolS *) 0, (long) 2, (char *) 0);
+  unsigned long nop = TIC_NOP_OPCODE;
 
-  /* We could use frag_align_pattern (n, nop_pattern, sizeof (nop_pattern));
-     to fill with our 32-bit nop opcode.  */
+  /* Because we are talking lwords, not bytes, adjust alignment to do words */
+  alignment += 2;
+  
+  if (alignment != 0 && !need_pass_2)
+    {
+      if (fill == NULL)
+        {
+          /*if (subseg_text_p (now_seg))*/  /* FIXME: doesn't work for .text for some reason */
+          frag_align_pattern( alignment, (const char *)&nop, sizeof(nop), max);
+          return 1;
+          /*else
+            frag_align (alignment, 0, max);*/
+       }
+      else if (len <= 1)
+       frag_align (alignment, *fill, max);
+      else
+       frag_align_pattern (alignment, fill, len, max);
+    }
+  
+  /* Return 1 to skip the default alignment function */
   return 1;
 }
 
 /* Look for and remove parallel instruction operator ||.  */
 void 
-c4x_start_line (void)
+tic4x_start_line (void)
 {
   char *s = input_line_pointer;
 
@@ -2584,13 +3000,15 @@ c4x_start_line (void)
       if (insn->in_use)
        {
          insn->parallel = 1;
-         input_line_pointer += 2;
+         input_line_pointer ++;
+          *input_line_pointer = ' ';
          /* So line counters get bumped.  */
          input_line_pointer[-1] = '\n';
        }
     }
   else
     {
+      /* Write out the previous insn here */
       if (insn->in_use)
        md_assemble (NULL);
       input_line_pointer = s;
@@ -2598,7 +3016,7 @@ c4x_start_line (void)
 }
 
 arelent *
-tc_gen_reloc (asection *seg, fixS *fixP)
+tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixP)
 {
   arelent *reloc;
 
@@ -2612,7 +3030,7 @@ tc_gen_reloc (asection *seg, fixS *fixP)
   if (reloc->howto == (reloc_howto_type *) NULL)
     {
       as_bad_where (fixP->fx_file, fixP->fx_line,
-                   "reloc %d not supported by object file format",
+                   "Reloc %d not supported by object file format",
                    (int) fixP->fx_r_type);
       return NULL;
     }
@@ -2624,4 +3042,3 @@ tc_gen_reloc (asection *seg, fixS *fixP)
 
   return reloc;
 }
-