Switch statement AVR-GCC

0

Hey so here is just a simple program i wrote in c, compiled under avr-gcc.. The corresponding assembly code is posted too.

Still cant understand what the assembly code for the switch statement is doing, any help would be great. thanks.

int main()
{

char myinput;

printf("Which option will you choose:\n");
printf("a) Program 1 \n");
printf("b) Program 2 \n");
scanf("%c", &myinput);

switch (myinput)
    {
                case 'a':
                printf("Run program 1\n");
                break;
        case 'b':
            {
                printf("Run program 2\n");
                printf("Please Wait\n");
                break;
            }
        default:
                printf("Invalid choice\n");
                break;
    }
    return 0;

return 0;

}

Assembly Code:

    switch (myinput)
+00000147:   900F        POP       R0             Pop register from stack
+00000148:   900F        POP       R0             Pop register from stack
+00000149:   900F        POP       R0             Pop register from stack
+0000014A:   900F        POP       R0             Pop register from stack
+0000014B:   8189        LDD       R24,Y+1        Load indirect with displacement
+0000014C:   3681        CPI       R24,0x61       Compare with immediate
+0000014D:   F019        BREQ      PC+0x04        Branch if equal
+0000014E:   3682        CPI       R24,0x62       Compare with immediate
+0000014F:   F459        BRNE      PC+0x0C        Branch if not equal
+00000150:   C003        RJMP      PC+0x0004      Relative jump
22:                         printf("Run program 1\n");
+00000151:   E38D        LDI       R24,0x3D       Load immediate
+00000152:   E092        LDI       R25,0x02       Load immediate
+00000153:   C009        RJMP      PC+0x000A      Relative jump
26:                         printf("Run program 2\n");
+00000154:   E48B        LDI       R24,0x4B       Load immediate
+00000155:   E092        LDI       R25,0x02       Load immediate
+00000156:   940E02A9    CALL      0x000002A9     Call subroutine
27:                         printf("Please Wait\n");
+00000158:   E589        LDI       R24,0x59       Load immediate
+00000159:   E092        LDI       R25,0x02       Load immediate
+0000015A:   C002        RJMP      PC+0x0003      Relative jump
31:                         printf("Invalid choice\n");
+0000015B:   E685        LDI       R24,0x65       Load immediate
+0000015C:   E092        LDI       R25,0x02       Load immediate
+0000015D:   940E02A9    CALL      0x000002A9     Call subroutine
38:       }
+0000015F:   E080        LDI       R24,0x00       Load immediate
+00000160:   E090        LDI       R25,0x00       Load immediate
+00000161:   900F        POP       R0             Pop register from stack
+00000162:   91CF        POP       R28            Pop register from stack
+00000163:   91DF        POP       R29            Pop register from stack
+00000164:   9508        RET                      Subroutine return

Thanks guys.

assembly
switch-statement
avr
avr-gcc
asked on Stack Overflow Jan 31, 2013 by fulhamHead

2 Answers

2

Here is a detailed explanation of what these lines mean:

+0000014B:   8189        LDD       R24,Y+1        Load indirect with displacement

Here the valueof myinput is copied from memory to register r24. In memory it is located at address Y+1. The value in Y is the address of the byte just before the myinput character.

+0000014C:   3681        CPI       R24,0x61       Compare with immediate
+0000014D:   F019        BREQ      PC+0x04        Branch if equal

Here the value of myinput (in r24) is compared to 0x61='a' (in ascii). If they are equal (myinput=='a') the execution continues at +00000151: (0x14D+0x4=0x0x151). Else the execution continues with the next instruction.

+0000014E:   3682        CPI       R24,0x62       Compare with immediate
+0000014F:   F459        BRNE      PC+0x0C        Branch if not equal
+00000150:   C003        RJMP      PC+0x0004      Relative jump

Here again the value of myinput (in r24) is compared to 0x62='b' (in ASCII), but now only if they're NOT equal (default case) the execution continues at +0000015B: (0x14F+0xC=0x0x15B). Else (myinput=='b') the next instruction is a jump to +00000154: (0x150+0x4=0x0x154).

22:                         printf("Run program 1\n");
+00000151:   E38D        LDI       R24,0x3D       Load immediate
+00000152:   E092        LDI       R25,0x02       Load immediate
+00000153:   C009        RJMP      PC+0x000A      Relative jump

In the 'a'-casethe argument (actually the memory address of the string) for the printf command is stored in r25:r24. Then the execution branches to the last printf call before the end of the switch statement at +0000015D:.

26:                         printf("Run program 2\n");
+00000154:   E48B        LDI       R24,0x4B       Load immediate
+00000155:   E092        LDI       R25,0x02       Load immediate
+00000156:   940E02A9    CALL      0x000002A9     Call subroutine
27:                         printf("Please Wait\n");
+00000158:   E589        LDI       R24,0x59       Load immediate
+00000159:   E092        LDI       R25,0x02       Load immediate
+0000015A:   C002        RJMP      PC+0x0003      Relative jump

In the 'b'-case, similarly to before, the address of the string to print is stored in r25:r24. Then the execution calls the printf subroutine at memory address0x000002A9. Then the address of the second string is loaded to r25:r24 and the execution jumps to the last call of printf before the end of the switch statement at +0000015E:.

Here one can see very well, that the strings are stored in memory, as the first string is 14 (0xE) bytes (chars) long and lies at 0x3D02; the next string lies at 0x3D02+0xE=0x4D02!!

31:                         printf("Invalid choice\n");
+0000015B:   E685        LDI       R24,0x65       Load immediate
+0000015C:   E092        LDI       R25,0x02       Load immediate
+0000015D:   940E02A9    CALL      0x000002A9     Call subroutine

In the default case, as before, the string is loaded to r25:r24 and printf is called.

38:       }
+0000015F:   E080        LDI       R24,0x00       Load immediate
+00000160:   E090        LDI       R25,0x00       Load immediate
+00000161:   900F        POP       R0             Pop register from stack
+00000162:   91CF        POP       R28            Pop register from stack
+00000163:   91DF        POP       R29            Pop register from stack
+00000164:   9508        RET                      Subroutine return

Cleaning up and return...

I hope this can help you out a bit (even though very late), and if not, may it help someone finding this post on a search while having similar problems!

answered on Stack Overflow Aug 18, 2015 by Fabio
1

Offset 0000014C compares "myInput" to 'a' (ASCII 97, hex 0x61) and if equal jumps to offset 00000151 (which is PC+4 at the points of BREQ, offset 0000014D, because the FETCH part of the pipeline is ahead of the EXECUTE part).

If the compare fails, it then compares to 'b' (offset 0000014E), and again branches accordingly.

If that fails, we jump to the last case.

Note there are subtleties in how we call printf (CALL 0x2A9), and where it returns.

answered on Stack Overflow Jan 31, 2013 by Nitzan Shaked

User contributions licensed under CC BY-SA 3.0