sdcc -v
9913 MINGW64
The test code:
#define PORT_A_KEY_LEFT 0x0004 #define PORT_A_KEY_RIGHT 0x0008 #define PORT_A_KEY_1 0x0010 unsigned int keystatus; unsigned char basestage; void InitPlayerConstants(); void InitSelectorStage() { unsigned char selected_stage=0; unsigned char keyfree=1; // Bucle while(1) { // Selector left if(keystatus&PORT_A_KEY_LEFT) { if(keyfree==1) if(selected_stage>0) selected_stage--; keyfree=0; } // Selector right else if(keystatus&PORT_A_KEY_RIGHT) { if(keyfree==1) if(selected_stage<4) selected_stage++; keyfree=0; } // No key else keyfree=1; // Play? if(keystatus&PORT_A_KEY_1) { basestage=selected_stage; InitPlayerConstants(); return; } } }
First correctly generated code with
sdcc -mz80 -S test.c --no-c-code-in-asm --no-peep
The peepholer will improve this code greatly but the no-peep is used so the nature of the code generation problem is clear.
_InitSelectorStage:: ld c, #0x00 ld b, #0x01 00118$: dec b jp NZ,00154$ ld a,#0x01 jp 00155$ 00154$: xor a,a 00155$: ld iy, #_keystatus bit 2, 0 (iy) jp NZ,00156$ jp 00113$ 00156$: or a, a jp Z, 00104$ ld a, c or a, a jp Z, 00104$ dec c 00104$: ld b, #0x00 jp 00114$ 00113$: ld iy, #_keystatus bit 3, 0 (iy) jp NZ,00157$ jp 00110$ 00157$: or a, a jp Z, 00108$ ld a, c sub a, #0x04 jp NC, 00108$ inc c 00108$: ld b, #0x00 jp 00114$ 00110$: ld b, #0x01 00114$: ld iy, #_keystatus bit 4, 0 (iy) jp NZ,00158$ jp 00118$ 00158$: ld iy, #_basestage ld 0 (iy), c call _InitPlayerConstants 00120$: ret
Register A is being set to the boolean value (keyfree == 1) and the test for (keyfree==1) is being pulled ahead of the if..else. IY is being used to test keystatus.
Incorrect code is generated when sdcc is told not to use IY
sdcc -mz80 -S test.c --no-c-code-in-asm --no-peep --reserve-regs-iy
_InitSelectorStage:: ld c, #0x00 ld b, #0x01 00118$: dec b jp NZ,00154$ ld a,#0x01 jp 00155$ 00154$: xor a,a 00155$: ld hl, #_keystatus ld a, (hl) and a, #0x04 jp NZ,00156$ jp 00113$ 00156$: or a, a jp Z, 00104$ ld a, c or a, a jp Z, 00104$ dec c 00104$: ld b, #0x00 jp 00114$ 00113$: ld hl, #_keystatus ld a, (hl) and a, #0x08 jp NZ,00157$ jp 00110$ 00157$: or a, a jp Z, 00108$ ld a, c sub a, #0x04 jp NC, 00108$ inc c 00108$: ld b, #0x00 jp 00114$ 00110$: ld b, #0x01 00114$: ld hl, #_keystatus ld a, (hl) and a, #0x10 jp NZ,00158$ jp 00118$ 00158$: ld hl, #_basestage ld (hl), c call _InitPlayerConstants 00120$: ret
The peepholer will also improved this code but it is starting with incorrect code. As in the correct case, register A is being set to boolean value (keyfree==1) ahead of the if..else. Because sdcc is not allowed to use IY it goes to using HL directly to access keyfree. However in order to read the byte there it, reads it with regster A, thus wiping out the stored boolean value:
ld hl, #_keystatus ld a, (hl) and a, #0x04
The peepholer for the correct case without reserve-regs-iy will result in very similar code but register A is not modified:
ld hl,#_keystatus+0 bit 2, (hl) jr Z,00113$
Fixed in revision [r9916].
Philipp