Patchwork rx: create interrupt vector aliases by attributes

login
register
mail settings
Submitter DJ Delorie
Date Nov. 15, 2012, 1:47 a.m.
Message ID <201211150147.qAF1lOXv021898@greed.delorie.com>
Download mbox | patch
Permalink /patch/199099/
State New
Headers show

Comments

DJ Delorie - Nov. 15, 2012, 1:47 a.m.
This patch allows the user to specify a vector number in an interrupt
attribute, allowing for more generic creation of vector tables.  Ok?

	* doc/extend.texi (Function Attributes): Document RX extensions to
	"interrupt" attribute.
	* config/rx/rx.c (has_interrupt_vector): New.
	(rx_output_function_prologue): If a function has an interrupt
	vector assigned, emit a vector-specific alias for it.
	(rx_handle_func_attribute): Allow args to attributes.
	(rx_attribute_table): Allow the interrupt attribute to take an
	argument.

Patch

Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 193523)
+++ gcc/doc/extend.texi	(working copy)
@@ -2892,12 +2892,39 @@  void __attribute__ ((interrupt, use_shad
 @end smallexample
 
 On RL78, use @code{brk_interrupt} instead of @code{interrupt} for
 handlers intended to be used with the @code{BRK} opcode (i.e.  those
 that must end with @code{RETB} instead of @code{RETI}).
 
+On RX targets, you can specify an interrupt vector number, which
+causes gcc to emit a vector-specific alias for the function:
+
+@smallexample
+void f () __attribute__((interrupt (15)));
+@end smallexample
+
+In the above example, an additional global symbol
+@code{__gcc_autovector_func_15} would be created to reference this
+function, which can be referenced by some other function or linker
+script to build the vector table:
+
+@smallexample
+extern __gcc_autovector_func_15() __attribute__((weak));
+@{ @dots{} __gcc_autovector_func_15; @dots{} @}
+
+.weak __gcc_autovector_func_15
+.long __gcc_autovector_func_15
+
+PROVIDE(__gcc_autovector_func_15=0)
+LONG (__gcc_autovector_func_15)
+@end smallexample
+
+Note that the PROVIDE must be outside any section block
+(i.e. @code{.text : @{ ... @} }) or else the value will be relocated
+and result in a non-zero address.
+
 @item interrupt_handler
 @cindex interrupt handler functions on the Blackfin, m68k, H8/300 and SH processors
 Use this attribute on the Blackfin, m68k, H8/300, H8/300H, H8S, and SH to
 indicate that the specified function is an interrupt handler.  The compiler
 generates function entry and exit sequences suitable for use in an
 interrupt handler when this attribute is present.
Index: gcc/config/rx/rx.c
===================================================================
--- gcc/config/rx/rx.c	(revision 193523)
+++ gcc/config/rx/rx.c	(working copy)
@@ -1184,12 +1184,44 @@  is_fast_interrupt_func (const_tree decl)
 static inline bool
 is_interrupt_func (const_tree decl)
 {
   return has_func_attr (decl, "interrupt");
 }
 
+/* Returns true if the provided function has the "vector" attribute.
+ If true, it also returns the vector in *RET if RET is not NULL.  */
+
+static inline bool
+has_interrupt_vector (const_tree decl, int *ret)
+{
+  tree vec_attr;
+  int rv;
+
+  if (decl == NULL_TREE)
+    decl = current_function_decl;
+
+  vec_attr =  lookup_attribute ("interrupt", DECL_ATTRIBUTES (decl));
+  if (!vec_attr)
+    return false;
+
+  vec_attr = TREE_VALUE (vec_attr);
+  if (!vec_attr)
+    return false;
+
+  vec_attr = TREE_VALUE (vec_attr);
+  if (!vec_attr)
+    return false;
+
+  if (TREE_CODE (vec_attr) != INTEGER_CST)
+    return false;
+
+  if (ret)
+    *ret = TREE_INT_CST_LOW (vec_attr);
+  return true;
+}
+
 /* Returns true if the provided function has the "naked" attribute.  */
 
 static inline bool
 is_naked_func (const_tree decl)
 {
   return has_func_attr (decl, "naked");
@@ -1768,12 +1800,27 @@  rx_expand_prologue (void)
 }
 
 static void
 rx_output_function_prologue (FILE * file,
 			     HOST_WIDE_INT frame_size ATTRIBUTE_UNUSED)
 {
+  int v;
+
+  if (has_interrupt_vector (NULL_TREE, &v))
+    {
+      if (0 <= v && v <= 255)
+	{
+	  asm_fprintf (file, "\t.global\t__gcc_autovector_func_%d\n", v);
+	  asm_fprintf (file, "__gcc_autovector_func_%d:\n", v);
+	}
+      else
+	{
+	  error ("interrupt vector %d must be in the range 0..255", v);
+	}
+    }
+
   if (is_fast_interrupt_func (NULL_TREE))
     asm_fprintf (file, "\t; Note: Fast Interrupt Handler\n");
 
   if (is_interrupt_func (NULL_TREE))
     asm_fprintf (file, "\t; Note: Interrupt Handler\n");
 
@@ -2549,13 +2596,12 @@  rx_handle_func_attribute (tree * node,
 			  tree   name,
 			  tree   args,
 			  int    flags ATTRIBUTE_UNUSED,
 			  bool * no_add_attrs)
 {
   gcc_assert (DECL_P (* node));
-  gcc_assert (args == NULL_TREE);
 
   if (TREE_CODE (* node) != FUNCTION_DECL)
     {
       warning (OPT_Wattributes, "%qE attribute only applies to functions",
 	       name);
       * no_add_attrs = true;
@@ -2572,13 +2618,13 @@  rx_handle_func_attribute (tree * node,
 const struct attribute_spec rx_attribute_table[] =
 {
   /* Name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
      affects_type_identity.  */
   { "fast_interrupt", 0, 0, true, false, false, rx_handle_func_attribute,
     false },
-  { "interrupt",      0, 0, true, false, false, rx_handle_func_attribute,
+  { "interrupt",      0, 1, true, false, false, rx_handle_func_attribute,
     false },
   { "naked",          0, 0, true, false, false, rx_handle_func_attribute,
     false },
   { NULL,             0, 0, false, false, false, NULL, false }
 };