__critical causes the prolog to insert:
ld a,i
di
push af
which saves the interrupt register to into the accumulator and then pushes it onto the stack.
The epilog is:
pop af
ret PO
ei
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:
#include <stdio.h>
int main(char* argv[], int argc)
{
argc; argv;
printf("Hello, World!");
return 0;
}
int test0(int a, int b)
{
return a+b;
}
int test0c(int a, int b) __critical
{
return a+b;
}
int test0n(int a, int b) __naked
{
return a+b;
}
int test0cn(int a, int b) __critical __naked
{
return a+b;
}
void test0i() __interrupt
{
__asm__("nop");
}
void test0in() __interrupt __naked
{
__asm__("nop");
}
void test0ic() __interrupt __critical
{
__asm__("nop");
}
And the test.asm file is:
;--------------------------------------------------------
; File Created by SDCC : free open source ANSI-C Compiler
; Version 3.5.2 #9283 (MINGW64)
; This file was generated Wed Sep 02 15:19:10 2015
;--------------------------------------------------------
.module test
.optsdcc -mz80
;--------------------------------------------------------
; Public variables in this module
;--------------------------------------------------------
.globl _test0ic
.globl _test0in
.globl _test0i
.globl _test0cn
.globl _test0n
.globl _test0c
.globl _test0
.globl _main
.globl _printf
;--------------------------------------------------------
; special function registers
;--------------------------------------------------------
;--------------------------------------------------------
; ram data
;--------------------------------------------------------
.area _DATA
;--------------------------------------------------------
; ram data
;--------------------------------------------------------
.area _INITIALIZED
;--------------------------------------------------------
; absolute external ram data
;--------------------------------------------------------
.area _DABS (ABS)
;--------------------------------------------------------
; global & static initialisations
;--------------------------------------------------------
.area _HOME
.area _GSINIT
.area _GSFINAL
.area _GSINIT
;--------------------------------------------------------
; Home
;--------------------------------------------------------
.area _HOME
.area _HOME
;--------------------------------------------------------
; code
;--------------------------------------------------------
.area _CODE
;test.c:3: int main(char* argv[], int argc)
; ---------------------------------
; Function main
; ---------------------------------
_main::
;test.c:6: printf("Hello, World!");
ld hl,#___str_0
push hl
call _printf
pop af
;test.c:7: return 0;
ld hl,#0x0000
ret
___str_0:
.ascii "Hello, World!"
.db 0x00
;test.c:10: int test0(int a, int b)
; ---------------------------------
; Function test0
; ---------------------------------
_test0::
;test.c:12: return a+b;
ld hl,#4
add hl,sp
ld iy,#2
add iy,sp
ld a,0 (iy)
add a, (hl)
ld d,a
ld a,1 (iy)
inc hl
adc a, (hl)
ld e,a
ld l, d
ld h, e
ret
;test.c:14: int test0c(int a, int b) __critical
; ---------------------------------
; Function test0c
; ---------------------------------
_test0c::
ld a,i
di
push af
;test.c:16: return a+b;
ld hl,#4
add hl,sp
ld iy,#2
add iy,sp
ld a,0 (iy)
add a, (hl)
ld d,a
ld a,1 (iy)
inc hl
adc a, (hl)
ld e,a
ld l, d
ld h, e
pop af
ret PO
ei
ret
;test.c:18: int test0n(int a, int b) __naked
; ---------------------------------
; Function test0n
; ---------------------------------
_test0n::
;test.c:20: return a+b;
ld hl,#4
add hl,sp
ld iy,#2
add iy,sp
ld a,0 (iy)
add a, (hl)
ld d,a
ld a,1 (iy)
inc hl
adc a, (hl)
ld e,a
ld l, d
ld h, e
;test.c:22: int test0cn(int a, int b) __critical __naked
; ---------------------------------
; Function test0cn
; ---------------------------------
_test0cn::
;test.c:24: return a+b;
ld hl,#4
add hl,sp
ld iy,#2
add iy,sp
ld a,0 (iy)
add a, (hl)
ld d,a
ld a,1 (iy)
inc hl
adc a, (hl)
ld e,a
ld l, d
ld h, e
;test.c:27: void test0i() __interrupt
; ---------------------------------
; Function test0i
; ---------------------------------
_test0i::
push af
push bc
push de
push hl
push iy
;test.c:29: __asm__("nop");
nop
pop iy
pop hl
pop de
pop bc
pop af
reti
;test.c:31: void test0in() __interrupt __naked
; ---------------------------------
; Function test0in
; ---------------------------------
_test0in::
;test.c:33: __asm__("nop");
nop
;test.c:35: void test0ic() __interrupt __critical
; ---------------------------------
; Function test0ic
; ---------------------------------
_test0ic::
push af
push bc
push de
push hl
push iy
;test.c:37: __asm__("nop");
nop
pop iy
pop hl
pop de
pop bc
pop af
retn
.area _CODE
.area _INITIALIZER
.area _CABS (ABS)
No comments:
Post a Comment