Critical Naked Interrupts and Unpromoted Characters -- In SDCC
• Mark
I decided to compile a test file just to see exactly what __critical, __naked, and __interrupt do. Here are the results.
__critical causes the prolog to insert:
which saves the interrupt register to into the accumulator and then pushes it onto the stack.
The epilog is:
which is curious because what’s that return on parity odd? Well, if the interrupts were already disabled when calling di, they shouldn’t be reenabled. It would be possible to use a reference count to keep track of nested __critical functions, but this works as well. When the ld a,i is executed, PO gets the current enabled/disabled state. If the P flag is PO, then the interrupts were disabled coming and won’t be enabled.
Is this better than a reference count? If it’s used lightly, cetainly. It’s a total of 7 bytes with 2 bytes overhead per nested call. A reference count would be 6 bytes, with how many every bytes are needed to store the count and use the count.
__naked causes the prolog and epilog to not generate. The code is generated according to the calling convention. But no registers are saved or restored, no return is generated, and function level
__critical doesn’t take effect because that inserts the critical code into the prolog and epilogs.
__interrupt causes function to save and restore AF, BC, DE, HL, and IY. The return is reti.
__naked __interrupt is equivalent to __naked since __interrupt only affects the prolog and epilog.
__critical __interrupt is used to emit the retn instead of reti for returning from a non-maskable interrupt.
Other testing also shows that the __critical { … } works as expected, putting the same di, ei, jp PO into the code itself.
Finally, a note on integer promotion of function arguments. SDCC doesn’t follow the C standard of promoting chars to ints. And thank goodness! Because although an int is 16 bits, the Z-80 works best with 8 bit data, so coercing it to 16 bits when it can be treated as 8 bit data would be counter productive.