\end_inset
for details on customizing startup.
+\layout Subsection
+
+Z80 Interrupt Service Routines
+\layout Standard
+
+The Z80 uses several different methods for determining the correct interrupt
+ vector depending on the hardware implementation.
+ Therefore, SDCC ignores the optional interrupt number and does not attempt
+ to generate an interrupt vector table.
+\layout Standard
+
+By default, SDCC generates code for a maskable interrupt, which uses an
+ RETI instruction to return from the interrupt.
+ To write an interrupt handler for the non-maskable interrupt, which needs
+ an RETN instruction instead, add the
+\emph on
+critical
+\emph default
+ keyword:
+\layout Verse
+
+
+\family typewriter
+void nmi_isr (void) critical interrupt
+\newline
+{
+\newline
+\SpecialChar ~
+\SpecialChar ~
+\SpecialChar ~
+\SpecialChar ~
+...
+
+\newline
+}
\layout Section
Enabling and Disabling Interrupts
ftype = operandType (IC_LEFT (ic));
- /* if critical function then turn interrupts off */
- if (IFFUNC_ISCRITICAL (ftype))
- emit2 ("!di");
-
/* if this is an interrupt service routine then save all potentially used registers. */
if (IFFUNC_ISISR (sym->type))
{
- emit2 ("!pusha");
+ if (!FUNC_ISNAKED( sym->type ))
+ {
+ emit2 ("!pusha");
+ }
+ }
+ else
+ {
+ /* if critical function then turn interrupts off */
+ if (IFFUNC_ISCRITICAL (sym->type))
+ {
+ emit2 ("!di");
+ }
}
/* PENDING: callee-save etc */
{
symbol *sym = OP_SYMBOL (IC_LEFT (ic));
- if (IFFUNC_ISISR (sym->type))
+
+ /* PENDING: calleeSave */
+ if (IS_Z80 && _G.omitFramePtr)
{
- wassertl (0, "Tried to close an interrupt support function");
+ if (_G.stack.offset)
+ emit2 ("!ldaspsp", _G.stack.offset);
}
- else
+ else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
{
- if (IFFUNC_ISCRITICAL (sym->type))
- emit2 ("!ei");
-
- /* PENDING: calleeSave */
-
- if (IS_Z80 && _G.omitFramePtr)
- {
- if (_G.stack.offset)
- emit2 ("!ldaspsp", _G.stack.offset);
- }
- else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
- {
- emit2 ("!leavexl", _G.stack.offset);
- }
- else if (_G.stack.offset)
- {
- emit2 ("!leavex", _G.stack.offset);
- }
- else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */
- {
- emit2 ("!leave");
- }
+ emit2 ("!leavexl", _G.stack.offset);
+ }
+ else if (_G.stack.offset)
+ {
+ emit2 ("!leavex", _G.stack.offset);
+ }
+ else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */
+ {
+ emit2 ("!leave");
+ }
+
+ if (_G.calleeSaves.pushedDE)
+ {
+ emit2 ("pop de");
+ _G.calleeSaves.pushedDE = FALSE;
+ }
- if (_G.calleeSaves.pushedDE)
- {
- emit2 ("pop de");
- _G.calleeSaves.pushedDE = FALSE;
- }
+ if (_G.calleeSaves.pushedBC)
+ {
+ emit2 ("pop bc");
+ _G.calleeSaves.pushedBC = FALSE;
+ }
- if (_G.calleeSaves.pushedBC)
- {
- emit2 ("pop bc");
- _G.calleeSaves.pushedBC = FALSE;
- }
+ if (options.profile)
+ {
+ emit2 ("!profileexit");
+ }
- if (options.profile)
+ /* if this is an interrupt service routine then restore all potentially used registers. */
+ if (IFFUNC_ISISR (sym->type))
+ {
+ if (!FUNC_ISNAKED( sym->type ))
{
- emit2 ("!profileexit");
+ emit2 ("!popa");
}
+ }
+ else
+ {
+ /* if critical function then turn interrupts back on */
+ if (IFFUNC_ISCRITICAL (sym->type))
+ emit2 ("!ei");
+ }
-
- if (options.debug && currFunc)
- {
- debugFile->writeEndFunction (currFunc, ic, 1);
- }
+ if (options.debug && currFunc)
+ {
+ debugFile->writeEndFunction (currFunc, ic, 1);
+ }
+ if (IFFUNC_ISISR (sym->type))
+ {
+ /* "critical interrupt" is used to imply NMI handler */
+ if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type))
+ emit2 ("retn");
+ else
+ emit2 ("reti");
+ }
+ else
+ {
/* Both banked and non-banked just ret */
emit2 ("ret");
-
- sprintf (buffer, "%s_end", sym->rname);
- emit2 ("!labeldef", buffer);
}
+
+ sprintf (buffer, "%s_end", sym->rname);
+ emit2 ("!labeldef", buffer);
+
_G.flushStatics = 1;
_G.stack.pushed = 0;
_G.stack.offset = 0;