diff --git a/cpu/ChangeLog b/cpu/ChangeLog
index faeb5a6e658aea790f49efe9d95743808fcc6991..bae9cccc4ee4d584b422d350b991d3eea59218ce 100644
--- a/cpu/ChangeLog
+++ b/cpu/ChangeLog
@@ -1,3 +1,21 @@
+2004-01-06  Alexandre Oliva  <aoliva@redhat.com>
+
+	2003-12-19  Alexandre Oliva  <aoliva@redhat.com>
+	* frv.opc (parse_ulo16, parse_uhi16, parse_d12): Fix some
+	cut&paste errors in shifting/truncating numerical operands.
+	2003-08-08  Alexandre Oliva  <aoliva@redhat.com>
+	* frv.opc (parse_ulo16): Parse gotofflo and gotofffuncdesclo.
+	(parse_uslo16): Likewise.
+	(parse_uhi16): Parse gotoffhi and gotofffuncdeschi.
+	(parse_d12): Parse gotoff12 and gotofffuncdesc12.
+	(parse_s12): Likewise.
+	2003-08-04  Alexandre Oliva  <aoliva@redhat.com>
+	* frv.opc (parse_ulo16): Parse gotlo and gotfuncdesclo.
+	(parse_uslo16): Likewise.
+	(parse_uhi16): Parse gothi and gotfuncdeschi.
+	(parse_d12): Parse got12 and gotfuncdesc12.
+	(parse_s12): Likewise.
+
 2003-10-10  Dave Brolley  <brolley@redhat.com>
 
 	* frv.cpu (dnpmop): New p-macro.
diff --git a/cpu/frv.opc b/cpu/frv.opc
index e149508edf4817819e8878caa3e9701ebdfee9fe..92b55867ee112a1bbe79dc3d127917d7af55e02c 100644
--- a/cpu/frv.opc
+++ b/cpu/frv.opc
@@ -897,7 +897,66 @@ parse_ulo16 (cd, strp, opindex, valuep)
 	  ++*strp;
 	  if (errmsg == NULL
 	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	    value >>= 16;
+	    value &= 0xffff;
+	  *valuep = value;
+	  return errmsg;
+	}
+      else if (strncasecmp (*strp + 1, "gotlo(", 6) == 0)
+	{
+	  *strp += 7;
+	  errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOTLO,
+				       &result_type, &value);
+	  if (**strp != ')')
+	    return "missing ')'";
+	  ++*strp;
+	  if (errmsg == NULL
+	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+	    value &= 0xffff;
+	  *valuep = value;
+	  return errmsg;
+	}
+      else if (strncasecmp (*strp + 1, "gotfuncdesclo(", 14) == 0)
+	{
+	  *strp += 15;
+	  errmsg = cgen_parse_address (cd, strp, opindex,
+				       BFD_RELOC_FRV_FUNCDESC_GOTLO,
+				       &result_type, &value);
+	  if (**strp != ')')
+	    return "missing ')'";
+	  ++*strp;
+	  if (errmsg == NULL
+	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+	    value &= 0xffff;
+	  *valuep = value;
+	  return errmsg;
+	}
+      else if (strncasecmp (*strp + 1, "gotofflo(", 9) == 0)
+	{
+	  *strp += 10;
+	  errmsg = cgen_parse_address (cd, strp, opindex,
+				       BFD_RELOC_FRV_GOTOFFLO,
+				       &result_type, &value);
+	  if (**strp != ')')
+	    return "missing ')'";
+	  ++*strp;
+	  if (errmsg == NULL
+	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+	    value &= 0xffff;
+	  *valuep = value;
+	  return errmsg;
+	}
+      else if (strncasecmp (*strp + 1, "gotofffuncdesclo(", 17) == 0)
+	{
+	  *strp += 18;
+	  errmsg = cgen_parse_address (cd, strp, opindex,
+				       BFD_RELOC_FRV_FUNCDESC_GOTOFFLO,
+				       &result_type, &value);
+	  if (**strp != ')')
+	    return "missing ')'";
+	  ++*strp;
+	  if (errmsg == NULL
+	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+	    value &= 0xffff;
 	  *valuep = value;
 	  return errmsg;
 	}
@@ -946,6 +1005,65 @@ parse_uslo16 (cd, strp, opindex, valuep)
 	  *valuep = value;
 	  return errmsg;
 	}
+      else if (strncasecmp (*strp + 1, "gotlo(", 6) == 0)
+	{
+	  *strp += 7;
+	  errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOTLO,
+				       &result_type, &value);
+	  if (**strp != ')')
+	    return "missing ')'";
+	  ++*strp;
+	  if (errmsg == NULL
+	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+	    value &= 0xffff;
+	  *valuep = value;
+	  return errmsg;
+	}
+      else if (strncasecmp (*strp + 1, "gotfuncdesclo(", 14) == 0)
+	{
+	  *strp += 15;
+	  errmsg = cgen_parse_address (cd, strp, opindex,
+				       BFD_RELOC_FRV_FUNCDESC_GOTLO,
+				       &result_type, &value);
+	  if (**strp != ')')
+	    return "missing ')'";
+	  ++*strp;
+	  if (errmsg == NULL
+	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+	    value &= 0xffff;
+	  *valuep = value;
+	  return errmsg;
+	}
+      else if (strncasecmp (*strp + 1, "gotofflo(", 9) == 0)
+	{
+	  *strp += 10;
+	  errmsg = cgen_parse_address (cd, strp, opindex,
+				       BFD_RELOC_FRV_GOTOFFLO,
+				       &result_type, &value);
+	  if (**strp != ')')
+	    return "missing ')'";
+	  ++*strp;
+	  if (errmsg == NULL
+	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+	    value &= 0xffff;
+	  *valuep = value;
+	  return errmsg;
+	}
+      else if (strncasecmp (*strp + 1, "gotofffuncdesclo(", 17) == 0)
+	{
+	  *strp += 18;
+	  errmsg = cgen_parse_address (cd, strp, opindex,
+				       BFD_RELOC_FRV_FUNCDESC_GOTOFFLO,
+				       &result_type, &value);
+	  if (**strp != ')')
+	    return "missing ')'";
+	  ++*strp;
+	  if (errmsg == NULL
+	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+	    value &= 0xffff;
+	  *valuep = value;
+	  return errmsg;
+	}
     }
   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
 }
@@ -991,6 +1109,65 @@ parse_uhi16 (cd, strp, opindex, valuep)
 	  *valuep = value;
 	  return errmsg;
 	}
+      else if (strncasecmp (*strp + 1, "gothi(", 6) == 0)
+	{
+	  *strp += 7;
+	  errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOTHI,
+				       &result_type, &value);
+	  if (**strp != ')')
+	    return "missing ')'";
+	  ++*strp;
+	  if (errmsg == NULL
+	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+	    value >>= 16;
+	  *valuep = value;
+	  return errmsg;
+	}
+      else if (strncasecmp (*strp + 1, "gotfuncdeschi(", 14) == 0)
+	{
+	  *strp += 15;
+	  errmsg = cgen_parse_address (cd, strp, opindex,
+				       BFD_RELOC_FRV_FUNCDESC_GOTHI,
+				       &result_type, &value);
+	  if (**strp != ')')
+	    return "missing ')'";
+	  ++*strp;
+	  if (errmsg == NULL
+	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+	    value >>= 16;
+	  *valuep = value;
+	  return errmsg;
+	}
+      else if (strncasecmp (*strp + 1, "gotoffhi(", 9) == 0)
+	{
+	  *strp += 10;
+	  errmsg = cgen_parse_address (cd, strp, opindex,
+				       BFD_RELOC_FRV_GOTOFFHI,
+				       &result_type, &value);
+	  if (**strp != ')')
+	    return "missing ')'";
+	  ++*strp;
+	  if (errmsg == NULL
+	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+	    value >>= 16;
+	  *valuep = value;
+	  return errmsg;
+	}
+      else if (strncasecmp (*strp + 1, "gotofffuncdeschi(", 17) == 0)
+	{
+	  *strp += 18;
+	  errmsg = cgen_parse_address (cd, strp, opindex,
+				       BFD_RELOC_FRV_FUNCDESC_GOTOFFHI,
+				       &result_type, &value);
+	  if (**strp != ')')
+	    return "missing ')'";
+	  ++*strp;
+	  if (errmsg == NULL
+	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+	    value >>= 16;
+	  *valuep = value;
+	  return errmsg;
+	}
     }
   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
 }
@@ -1073,6 +1250,53 @@ parse_d12 (cd, strp, opindex, valuep)
           *valuep = value;
           return errmsg;
         }
+      else if (strncasecmp (*strp + 1, "got12(", 6) == 0)
+	{
+	  *strp += 7;
+	  errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOT12,
+				       &result_type, &value);
+	  if (**strp != ')')
+	    return "missing ')'";
+	  ++*strp;
+	  *valuep = value;
+	  return errmsg;
+	}
+      else if (strncasecmp (*strp + 1, "gotfuncdesc12(", 14) == 0)
+	{
+	  *strp += 15;
+	  errmsg = cgen_parse_address (cd, strp, opindex,
+				       BFD_RELOC_FRV_FUNCDESC_GOT12,
+				       &result_type, &value);
+	  if (**strp != ')')
+	    return "missing ')'";
+	  ++*strp;
+	  *valuep = value;
+	  return errmsg;
+	}
+      else if (strncasecmp (*strp + 1, "gotoff12(", 9) == 0)
+	{
+	  *strp += 10;
+	  errmsg = cgen_parse_address (cd, strp, opindex,
+				       BFD_RELOC_FRV_GOTOFF12,
+				       &result_type, &value);
+	  if (**strp != ')')
+	    return "missing ')'";
+	  ++*strp;
+	  *valuep = value;
+	  return errmsg;
+	}
+      else if (strncasecmp (*strp + 1, "gotofffuncdesc12(", 17) == 0)
+	{
+	  *strp += 18;
+	  errmsg = cgen_parse_address (cd, strp, opindex,
+				       BFD_RELOC_FRV_FUNCDESC_GOTOFF12,
+				       &result_type, &value);
+	  if (**strp != ')')
+	    return "missing ')'";
+	  ++*strp;
+	  *valuep = value;
+	  return errmsg;
+	}
     }
   return cgen_parse_signed_integer (cd, strp, opindex, valuep);
 }
@@ -1101,6 +1325,56 @@ parse_s12 (cd, strp, opindex, valuep)
       *valuep = value;
       return errmsg;
     }
+  else if ((**strp == '#' || **strp == '%')
+	   && strncasecmp (*strp + 1, "got12(", 6) == 0)
+    {
+      *strp += 7;
+      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOT12,
+				   &result_type, &value);
+      if (**strp != ')')
+	return "missing ')'";
+      ++*strp;
+      *valuep = value;
+      return errmsg;
+    }
+  else if ((**strp == '#' || **strp == '%')
+	   && strncasecmp (*strp + 1, "gotfuncdesc12(", 14) == 0)
+    {
+      *strp += 15;
+      errmsg = cgen_parse_address (cd, strp, opindex,
+				   BFD_RELOC_FRV_FUNCDESC_GOT12,
+				   &result_type, &value);
+      if (**strp != ')')
+	return "missing ')'";
+      ++*strp;
+      *valuep = value;
+      return errmsg;
+    }
+  else if ((**strp == '#' || **strp == '%')
+	   && strncasecmp (*strp + 1, "gotoff12(", 9) == 0)
+    {
+      *strp += 10;
+      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOTOFF12,
+				   &result_type, &value);
+      if (**strp != ')')
+	return "missing ')'";
+      ++*strp;
+      *valuep = value;
+      return errmsg;
+    }
+  else if ((**strp == '#' || **strp == '%')
+	   && strncasecmp (*strp + 1, "gotofffuncdesc12(", 17) == 0)
+    {
+      *strp += 18;
+      errmsg = cgen_parse_address (cd, strp, opindex,
+				   BFD_RELOC_FRV_FUNCDESC_GOTOFF12,
+				   &result_type, &value);
+      if (**strp != ')')
+	return "missing ')'";
+      ++*strp;
+      *valuep = value;
+      return errmsg;
+    }
   else
     {
       if (**strp == '#')