Interrupts with GCC/EGCS
Michael Schwingen
rincewind@discworld.dascon.de
Fri Mar 12 13:03:00 GMT 1999
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);
+ }
+
+
More information about the crossgcc
mailing list