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:

1  ld a,i
2  di
3  push af

which saves the interrupt register to into the accumulator and then pushes it onto the stack.

The epilog is:

1  pop af
2  ret po
3  ei
4  ret

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.

For reference, the test.c file is:

 1 #include <stdio.h>
 2 
 3 int main(char* argv[], int argc)
 4 {
 5     argc; argv;
 6     printf("Hello, World!");
 7     return 0;
 8 }
 9 
10 int test0(int a, int b)
11 {
12  return a+b;
13 }
14 int test0c(int a, int b) __critical
15 {
16  return a+b;
17 }
18 int test0n(int a, int b) __naked
19 {
20  return a+b;
21 }
22 int test0cn(int a, int b) __critical __naked
23 {
24  return a+b;
25 }
26 
27 void test0i() __interrupt
28 {
29  __asm__("nop");
30 }
31 void test0in() __interrupt __naked
32 {
33  __asm__("nop");
34 }
35 void test0ic() __interrupt __critical
36 {
37  __asm__("nop");
38 }

And the test.asm file is:

  1 ;--------------------------------------------------------
  2 ; File Created by SDCC : free open source ANSI-C Compiler
  3 ; Version 3.5.2 #9283 (MINGW64)
  4 ; This file was generated Wed Sep 02 15:19:10 2015
  5 ;--------------------------------------------------------
  6  .module test
  7  .optsdcc -mz80
  8  
  9 ;--------------------------------------------------------
 10 ; Public variables in this module
 11 ;--------------------------------------------------------
 12  .globl _test0ic
 13  .globl _test0in
 14  .globl _test0i
 15  .globl _test0cn
 16  .globl _test0n
 17  .globl _test0c
 18  .globl _test0
 19  .globl _main
 20  .globl _printf
 21 ;--------------------------------------------------------
 22 ; special function registers
 23 ;--------------------------------------------------------
 24 ;--------------------------------------------------------
 25 ; ram data
 26 ;--------------------------------------------------------
 27  .area _DATA
 28 ;--------------------------------------------------------
 29 ; ram data
 30 ;--------------------------------------------------------
 31  .area _INITIALIZED
 32 ;--------------------------------------------------------
 33 ; absolute external ram data
 34 ;--------------------------------------------------------
 35  .area _DABS (ABS)
 36 ;--------------------------------------------------------
 37 ; global & static initialisations
 38 ;--------------------------------------------------------
 39  .area _HOME
 40  .area _GSINIT
 41  .area _GSFINAL
 42  .area _GSINIT
 43 ;--------------------------------------------------------
 44 ; Home
 45 ;--------------------------------------------------------
 46  .area _HOME
 47  .area _HOME
 48 ;--------------------------------------------------------
 49 ; code
 50 ;--------------------------------------------------------
 51  .area _CODE
 52 ;test.c:3: int main(char* argv[], int argc)
 53 ; ---------------------------------
 54 ; Function main
 55 ; ---------------------------------
 56 _main::
 57 ;test.c:6: printf("Hello, World!");
 58  ld hl,#___str_0
 59  push hl
 60  call _printf
 61  pop af
 62 ;test.c:7: return 0;
 63  ld hl,#0x0000
 64  ret
 65 ___str_0:
 66  .ascii "Hello, World!"
 67  .db 0x00
 68 ;test.c:10: int test0(int a, int b)
 69 ; ---------------------------------
 70 ; Function test0
 71 ; ---------------------------------
 72 _test0::
 73 ;test.c:12: return a+b;
 74  ld hl,#4
 75  add hl,sp
 76  ld iy,#2
 77  add iy,sp
 78  ld a,0 (iy)
 79  add a, (hl)
 80  ld d,a
 81  ld a,1 (iy)
 82  inc hl
 83  adc a, (hl)
 84  ld e,a
 85  ld l, d
 86  ld h, e
 87  ret
 88 ;test.c:14: int test0c(int a, int b) __critical
 89 ; ---------------------------------
 90 ; Function test0c
 91 ; ---------------------------------
 92 _test0c::
 93  ld a,i
 94  di
 95  push af
 96 ;test.c:16: return a+b;
 97  ld hl,#4
 98  add hl,sp
 99  ld iy,#2
100  add iy,sp
101  ld a,0 (iy)
102  add a, (hl)
103  ld d,a
104  ld a,1 (iy)
105  inc hl
106  adc a, (hl)
107  ld e,a
108  ld l, d
109  ld h, e
110  pop af
111  ret PO
112  ei
113  ret
114 ;test.c:18: int test0n(int a, int b) __naked
115 ; ---------------------------------
116 ; Function test0n
117 ; ---------------------------------
118 _test0n::
119 ;test.c:20: return a+b;
120  ld hl,#4
121  add hl,sp
122  ld iy,#2
123  add iy,sp
124  ld a,0 (iy)
125  add a, (hl)
126  ld d,a
127  ld a,1 (iy)
128  inc hl
129  adc a, (hl)
130  ld e,a
131  ld l, d
132  ld h, e
133 ;test.c:22: int test0cn(int a, int b) __critical __naked
134 ; ---------------------------------
135 ; Function test0cn
136 ; ---------------------------------
137 _test0cn::
138 ;test.c:24: return a+b;
139  ld hl,#4
140  add hl,sp
141  ld iy,#2
142  add iy,sp
143  ld a,0 (iy)
144  add a, (hl)
145  ld d,a
146  ld a,1 (iy)
147  inc hl
148  adc a, (hl)
149  ld e,a
150  ld l, d
151  ld h, e
152 ;test.c:27: void test0i() __interrupt
153 ; ---------------------------------
154 ; Function test0i
155 ; ---------------------------------
156 _test0i::
157  push af
158  push bc
159  push de
160  push hl
161  push iy
162 ;test.c:29: __asm__("nop");
163  nop
164  pop iy
165  pop hl
166  pop de
167  pop bc
168  pop af
169  reti
170 ;test.c:31: void test0in() __interrupt __naked
171 ; ---------------------------------
172 ; Function test0in
173 ; ---------------------------------
174 _test0in::
175 ;test.c:33: __asm__("nop");
176  nop
177 ;test.c:35: void test0ic() __interrupt __critical
178 ; ---------------------------------
179 ; Function test0ic
180 ; ---------------------------------
181 _test0ic::
182  push af
183  push bc
184  push de
185  push hl
186  push iy
187 ;test.c:37: __asm__("nop");
188  nop
189  pop iy
190  pop hl
191  pop de
192  pop bc
193  pop af
194  retn
195  .area _CODE
196  .area _INITIALIZER
197  .area _CABS (ABS)