This is the mail archive of the crossgcc@cygnus.com mailing list for the crossgcc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: Interrupts with GCC/EGCS


On Wed, Mar 10, 1999 at 12:37:21PM +1100, Brendan Simon wrote:

> Some time ago I asked about interrupt keywords with egcs.  Jeff kindly
> responded with the above message.
> How do if the interrupt keyword exists for a particular target.  I am
> interested in 68k and powerpc.

Hm - I just did that. The patch could need some testing, but on my test
cases, it seemed to work fine.

It is mostly stolen from the NEC V850 target - note that #pragma interrupt
and __attribute((interrupt)) in the Hitachi SH target (where I looked first
for example code) seem to be broken because they use global variables ...

> What is the syntax to the attribute ?  Is it the same for all supported
> targets or is it target dependent ?

I used __attribute__((interrupt)). When set on a function, all modified
registers are saved and the function terminates using rte instead of
rts/rtd.

Note that you can not call an interrupt function from normal code, and it
might not be a good idea to declare them anything except void(void).

I'll attach the patch, comments are welcome. The patch is against
egcs-1.1b, but other versions should work, too.



volatile int x;

void __attribute__((interrupt)) intr(void)
{
  x++;
}


.comm _x,2
        .even
.globl _intr
_intr:
        move.l %d0,-(%sp)
        move.w _x,%d0
        addq.w #1,%d0
        move.w %d0,_x
        move.l (%sp)+,%d0
        rte


cu
Michael
-- 
Michael Schwingen, Ahornstrasse 36, 52074 Aachen
*** m68k.h.orig	Sat Mar  6 22:34:40 1999
--- m68k.h	Sun Mar  7 00:26:45 1999
***************
*** 2124,2129 ****
--- 2124,2138 ----
  extern void finalize_pic ();
  extern void override_options ();
  
+ 
+ /* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS
+    is a valid machine specific attribute for DECL.
+    The attributes in ATTRIBUTES have previously been assigned to DECL.  */
+ extern int m68k_valid_machine_decl_attribute ();
+ #define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \
+ m68k_valid_machine_decl_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS)
+ 
+ 
  
  /*
  Local variables:
*** m68k.c.orig	Sat Mar  6 22:34:37 1999
--- m68k.c	Sun Mar  7 01:03:29 1999
***************
*** 171,176 ****
--- 171,177 ----
    extern char call_used_regs[];
    int fsize = (size + 3) & -4;
    int cfa_offset = INCOMING_FRAME_SP_OFFSET, cfa_store_offset = cfa_offset;
+   int interrupt_handler = m68k_interrupt_function_p (current_function_decl);
    
  
    if (frame_pointer_needed)
***************
*** 308,314 ****
      }
  #ifdef SUPPORT_SUN_FPA
    for (regno = 24; regno < 56; regno++)
!     if (regs_ever_live[regno] && ! call_used_regs[regno])
        {
  #ifdef MOTOROLA
  	asm_fprintf (stream, "\tfpmovd %s,-(%Rsp)\n",
--- 309,315 ----
      }
  #ifdef SUPPORT_SUN_FPA
    for (regno = 24; regno < 56; regno++)
!     if (regs_ever_live[regno] && (!call_used_regs[regno] || interrupt_handler))
        {
  #ifdef MOTOROLA
  	asm_fprintf (stream, "\tfpmovd %s,-(%Rsp)\n",
***************
*** 334,340 ****
    if (TARGET_68881)
      {
        for (regno = 16; regno < 24; regno++)
! 	if (regs_ever_live[regno] && ! call_used_regs[regno])
  	  {
  	    mask |= 1 << (regno - 16);
  	    num_saved_regs++;
--- 335,341 ----
    if (TARGET_68881)
      {
        for (regno = 16; regno < 24; regno++)
! 	if (regs_ever_live[regno] && (!call_used_regs[regno] || interrupt_handler))
  	  {
  	    mask |= 1 << (regno - 16);
  	    num_saved_regs++;
***************
*** 367,373 ****
        num_saved_regs = 0;
      }
    for (regno = 0; regno < 16; regno++)
!     if (regs_ever_live[regno] && ! call_used_regs[regno])
        {
          mask |= 1 << (15 - regno);
          num_saved_regs++;
--- 368,374 ----
        num_saved_regs = 0;
      }
    for (regno = 0; regno < 16; regno++)
!     if (regs_ever_live[regno] && (!call_used_regs[regno] || interrupt_handler))
        {
          mask |= 1 << (15 - regno);
          num_saved_regs++;
***************
*** 499,504 ****
--- 500,506 ----
  use_return_insn ()
  {
    int regno;
+   int interrupt_handler = m68k_interrupt_function_p (current_function_decl);
  
    if (!reload_completed || frame_pointer_needed || get_frame_size () != 0)
      return 0;
***************
*** 507,513 ****
       separate layout routine to perform the common work.  */
    
    for (regno = 0 ; regno < FIRST_PSEUDO_REGISTER ; regno++)
!     if (regs_ever_live[regno] && ! call_used_regs[regno])
        return 0;
    
    return 1;
--- 509,515 ----
       separate layout routine to perform the common work.  */
    
    for (regno = 0 ; regno < FIRST_PSEUDO_REGISTER ; regno++)
!     if (regs_ever_live[regno] && (!call_used_regs[regno] || interrupt_handler))
        return 0;
    
    return 1;
***************
*** 535,540 ****
--- 537,543 ----
    int big = 0;
    rtx insn = get_last_insn ();
    int restore_from_sp = 0;
+   int interrupt_handler = m68k_interrupt_function_p (current_function_decl);
    
    /* If the last insn was a BARRIER, we don't have to write any code.  */
    if (GET_CODE (insn) == NOTE)
***************
*** 560,566 ****
    nregs = 0;  fmask = 0; fpoffset = 0;
  #ifdef SUPPORT_SUN_FPA
    for (regno = 24 ; regno < 56 ; regno++)
!     if (regs_ever_live[regno] && ! call_used_regs[regno])
        nregs++;
    fpoffset = nregs * 8;
  #endif
--- 563,569 ----
    nregs = 0;  fmask = 0; fpoffset = 0;
  #ifdef SUPPORT_SUN_FPA
    for (regno = 24 ; regno < 56 ; regno++)
!     if (regs_ever_live[regno] && (!call_used_regs[regno] || interrupt_handler))
        nregs++;
    fpoffset = nregs * 8;
  #endif
***************
*** 568,574 ****
    if (TARGET_68881)
      {
        for (regno = 16; regno < 24; regno++)
! 	if (regs_ever_live[regno] && ! call_used_regs[regno])
  	  {
  	    nregs++;
  	    fmask |= 1 << (23 - regno);
--- 571,577 ----
    if (TARGET_68881)
    {
      for (regno = 16; regno < 24; regno++)
!       if (regs_ever_live[regno] && (!call_used_regs[regno] || interrupt_handler))
        {
  	nregs++;
  	fmask |= 1 << (23 - regno);
***************
*** 579,585 ****
    if (frame_pointer_needed)
      regs_ever_live[FRAME_POINTER_REGNUM] = 0;
    for (regno = 0; regno < 16; regno++)
!     if (regs_ever_live[regno] && ! call_used_regs[regno])
        {
          nregs++;
  	mask |= 1 << regno;
--- 582,588 ----
    if (frame_pointer_needed)
      regs_ever_live[FRAME_POINTER_REGNUM] = 0;
    for (regno = 0; regno < 16; regno++)
!     if (regs_ever_live[regno] && (!call_used_regs[regno] || interrupt_handler))
      {
        nregs++;
        mask |= 1 << regno;
***************
*** 729,735 ****
      }
    if (fpoffset != 0)
      for (regno = 55; regno >= 24; regno--)
!       if (regs_ever_live[regno] && ! call_used_regs[regno])
          {
  	  if (big)
  	    {
--- 732,738 ----
      }
    if (fpoffset != 0)
      for (regno = 55; regno >= 24; regno--)
!       if (regs_ever_live[regno] && (!call_used_regs[regno] || interrupt_handler))
          {
  	  if (big)
  	    {
***************
*** 839,848 ****
--- 842,858 ----
  #endif
  	}
      }
+   if (interrupt_handler)
+   {
+     fprintf (stream, "\trte\n");
+   }
+   else
+   {
      if (current_function_pops_args)
        asm_fprintf (stream, "\trtd %0I%d\n", current_function_pops_args);
      else
        fprintf (stream, "\trts\n");
+   }
  }
  
  /* Similar to general_operand, but exclude stack_pointer_rtx.  */
***************
*** 3391,3393 ****
--- 3401,3446 ----
      }
    return "eor%.l %2,%0";
  }
+ 
+ /* Return nonzero if ATTR is a valid attribute for DECL.
+    ATTRIBUTES are any existing attributes and ARGS are the arguments
+    supplied with ATTR.
+ 
+    Supported attributes:
+ 
+    interrupt -- specifies this function is an interrupt handler.
+ */
+ 
+ int
+ m68k_valid_machine_decl_attribute (decl, attributes, attr, args)
+      tree decl;
+      tree attributes;
+      tree attr;
+      tree args;
+ {
+   if (args != NULL_TREE)
+     return 0;
+ 
+   if (is_attribute_p ("interrupt", attr))
+     return TREE_CODE (decl) == FUNCTION_DECL;
+ 
+   return 0;
+ }
+ 
+ /* Return nonzero if FUNC is an interrupt function as specified by the
+    "interrupt" attribute.  */
+ 
+ int
+ m68k_interrupt_function_p(func)
+      tree func;
+ {
+   tree a;
+ 
+   if (TREE_CODE (func) != FUNCTION_DECL)
+     return 0;
+ 
+   a = lookup_attribute ("interrupt", DECL_MACHINE_ATTRIBUTES (func));
+   return (a != NULL_TREE);
+ }
+ 
+