Codestück für Mega8 verkleinern (Flash reicht nicht).

OP #1817499
Lesenswert?

Hi

Ich hab durch zufall herausgefunden, dass folgendes Codestück 3KB des 
Megas verbraucht, und darum reicht mir der Speicherplatz nicht.
1
switch(key)
2
        {
3
            case 2: 
4
                if(digit == 0)
5
                    digit = 8;
6
                while(!((uint8_t)(1<<--digit) & mask))
7
                    if(digit < 1)
8
                        digit = 8;
9
                _delay_ms(100);
10
                seconds10 = 0;
11
                break;
12
            case 4:
13
            case 6:
14
                pre = key - 5;
15
                switch(mode)
16
                {
17
                    case MODE_HOUR_MIN:
18
                         Add(&currentGame[digit / 4].time, valency[digit % 4] * pre, MAX_TIME);
19
                         break;
20
                    case MODE_SEC:
21
                         Add(&currentGame[digit / 4].time, valency[digit % 4] * pre, MAX_TIME);
22
                         break;
23
                    case MODE_GUILLOTINE1:
24
                    case MODE_GUILLOTINE2:
25
                    case MODE_GUILLOTINE3:
26
                    case MODE_GUILLOTINE4:
27
                    case MODE_GUILLOTINE5:
28
                    case MODE_GUILLOTINE6:
29
                    case MODE_GUILLOTINE7:
30
                        for(uint8_t i = 0; i < 2; i++)
31
                            Add(&currentGame[i].guillotine[mode - MODE_GUILLOTINE1], valency[digit % 4] * pre, MAX_GUILLOTINE);
32
                        break;
33
                    case MODE_BONUS:
34
                        for(uint8_t i = 0; i < 2; i++)
35
                            Add(&currentGame[i].bonus, valency[digit % 4] * pre, MAX_BONUS);
36
                    case MODE_GUILLOTINE_COUNT:
37
                        for(uint8_t i = 0; i < 2; i++)
38
                            Add(&currentGame[current].options, (1 << 5), 224);
39
                        break;
40
                    case MODE_MOVES_COUNT1:
41
                    case MODE_MOVES_COUNT2:
42
                    case MODE_MOVES_COUNT3:
43
                    case MODE_MOVES_COUNT4:
44
                    case MODE_MOVES_COUNT5:
45
                    case MODE_MOVES_COUNT6:
46
                    case MODE_MOVES_COUNT7:   
47
                        for(uint8_t i = 0; i < 2; i++)
48
                            Add(&currentGame[current].moves[mode - MODE_MOVES_COUNT1], valency10[digit % 4] * pre, 7);
49
                        break;
50
                    case MODE_MOVES:
51
                        Add(&moves, valency10[digit % 4] * pre, MAX_MOVES);
52
                        break;
53
                    _delay_ms(50);
54
                };
55
                break;
56
            case 5:
57
                WaitForKeyUp();
58
                return FINISHED;
59
                break;
60
            case 8:
61
            if(digit > 6)
62
                digit = 255;
63
                while(!((uint8_t)(1<<++digit) & mask))
64
                    if(digit > 6)
65
                        digit = 255;
66
                _delay_ms(100);
67
                seconds10 = 0;
68
                break;
69
            case 9:
70
                return ABORT;
71
                break;
72
        };
Weiß jemand wie ich das verkleinern kann. Compiler Optimiert schon auf 
Größe.
Das komische: Wenn ich die case 4 und 6 auseinandernehme und das ganze 
ohne die Addfunktion schreibe, komm ich auf ein viertel der Größe, 
allerdings steht dann alles doppelt da und ich würde es lieber mit so 
und damit übersichtlicher machen.
Gast #1817545
Lesenswert?

Samuel K. schrieb:
> Kann man den Code vielleicht noch mehr optimieren, bzw. ist es so
> sinnvoll das mit switch zu machen, oder gibt es da bessere
> Möglichkeiten?
so schlimm ist der code nicht. Aber am meisten kann man sparen wenn man 
die genau funktion eines Programmes kennt. Leider kann man anhand der 
paar zeilen nicht wirklihc erkennen was das ding genau macht.
OP #1817554
Lesenswert?

Die Funktion regelt die Eingabe einer Schachuhr. Die Funktion KeyRo 
bekommt da als Argumente ein Modus, der angibt was eingestellt wird, und 
das wird in der switch abgefragt. Die Maske bestimmt dabei nur welche 
Digits der 8stelligen 7Segment Anzeige benutzt werden.

GetKey gibt eine Taste entprellt zurück sobald sie gedrückt ist.

Hier ist nochmal der korrigierte Code, da ein paar kleine Fehler in 
KeyRo drin waren (ich konnte ihmnja nicht testen, da er zu groß war).
1
uint8_t KeyRo(uint8_t mask, uint8_t mode)
2
{
3
    uint8_t digit = 255;
4
    while(!((uint8_t)(1<<++digit) & mask))
5
        if(digit > 6)
6
            return ABORT;
7
    while(1)
8
    {
9
        int8_t pre = 5;
10
        uint8_t key = 255;
11
        while(key == 255)
12
            key = GetKey();
13
        switch(key)
14
        {
15
            case 2: 
16
                if(digit == 0)
17
                    digit = 8;
18
                while(!((uint8_t)(1<<--digit) & mask))
19
                    if(digit < 1)
20
                        digit = 8;
21
                _delay_ms(100);
22
                seconds10 = 0;
23
                break;
24
            case 4:
25
            case 6:
26
                pre -= key;
27
                switch(mode)
28
                {
29
                    case MODE_HOUR_MIN:
30
                         Add(&currentGame[digit / 4].time, (int32_t)valency[digit % 4] * pre, MAX_TIME);
31
                         break;
32
                    case MODE_SEC:
33
                         Add(&currentGame[digit / 4].time, valency[digit % 4] * pre, MAX_TIME);
34
                         break;
35
                    case MODE_GUILLOTINE1:
36
                    case MODE_GUILLOTINE2:
37
                    case MODE_GUILLOTINE3:
38
                    case MODE_GUILLOTINE4:
39
                    case MODE_GUILLOTINE5:
40
                    case MODE_GUILLOTINE6:
41
                    case MODE_GUILLOTINE7:
42
                        for(uint8_t i = 0; i < 2; i++)
43
                            Add(&currentGame[i].guillotine[mode - MODE_GUILLOTINE1], valency[digit % 4] * pre, MAX_GUILLOTINE);
44
                        break;
45
                    case MODE_BONUS:
46
                        for(uint8_t i = 0; i < 2; i++)
47
                            Add(&currentGame[i].bonus, valency[digit % 4] * pre, MAX_BONUS);
48
                    case MODE_GUILLOTINE_COUNT:
49
                        for(uint8_t i = 0; i < 2; i++)
50
                            Add(&currentGame[current].options, (1 << 5), 224);
51
                        break;
52
                    case MODE_MOVES_COUNT1:
53
                    case MODE_MOVES_COUNT2:
54
                    case MODE_MOVES_COUNT3:
55
                    case MODE_MOVES_COUNT4:
56
                    case MODE_MOVES_COUNT5:
57
                    case MODE_MOVES_COUNT6:
58
                    case MODE_MOVES_COUNT7:   
59
                        for(uint8_t i = 0; i < 2; i++)
60
                            Add(&currentGame[current].moves[mode - MODE_MOVES_COUNT1], valency10[digit % 4] * pre, 7);
61
                        break;
62
                    case MODE_MOVES:
63
                        Add(&moves, valency10[digit % 4] * pre, MAX_MOVES);
64
                        break;
65
                };
66
                _delay_ms(50);
67
                break;
68
            case 5:
69
                WaitForKeyUp();
70
                return FINISHED;
71
                break;
72
            case 8:
73
            if(digit > 6)
74
                digit = 255;
75
                while(!((uint8_t)(1<<++digit) & mask))
76
                    if(digit > 6)
77
                        digit = 255;
78
                _delay_ms(100);
79
                seconds10 = 0;
80
                break;
81
            case 9:
82
                return ABORT;
83
                break;
84
        };
85
        //Show on Display, but first set the time to show
86
        SetTime();
87
        //Now we can call Show to show the time
88
        Show(digit, mode);
89
    }
#1817557
Lesenswert?

Switch ist schon recht effektiv.
Aber man kennt von Deinen Variablen nicht den Typ, daher kann man keine 
Optimierungen angeben.

Versuche, möglichst kleine Typen zu nehmen (uint8_t) und möglichst wenig 
globale Variablen.

Wenn Du Code postest, sollte er auch compilierbar sein, d.h. Prototypen 
für alle benutzten Variablen, Funktionen und Macrodefinitionen!
Im Assemblerlisting kann man nämlich am besten sehen, wo es klemmt.


Peter
Moderator Persönliche Seite #1817686
Lesenswert?

Peter Dannegger schrieb:
> Switch ist schon recht effektiv.

Bei Mehrfach-Cases (wie in diesem Fall) kann der Schuss aber auch nach 
hinten losgehen. Ich habe schon erlebt, dass hier eine if-else-if-Kette 
mit Or-Verknüpfung statt der Mehrfach-Cases wesentlich kleineren Code 
erzeugt. Vielleicht sollte Samuel den "Unter-Switch" für die Fälle 4 und 
6 mal als if-else-if-Kette umformulieren.

Gruß,

Frank
#1817805
Lesenswert?

Samuel K. schrieb:
> Ok, hier ist der ganze Code zum kompilieren.


Paßt doch bequem rein:
1
AVR Memory Usage
2
----------------
3
Device: atmega8
4

5
Program:    6290 bytes (76.8% Full)
6
(.text + .data + .bootloader)
7

8
Data:        138 bytes (13.5% Full)
9
(.data + .bss + .noinit)


Hier mal ein paar Optimierungsschalter:
1
-fno-inline-small-functions
2
-fno-split-wide-types
3
-fno-move-loop-invariants
4
-Wl,--relax
5
--combine -fwhole-program


Allerdings solltest Du Dich mal um die Warnungen kümmern, z.B.:
1
CHESS.C:62: warning: excess elements in array initializer
2
CHESS.C:62: warning: (near initialization for 'Games')

Entweder Du läßt die [] leer oder Du schreibst die richtige Anzahl rein.


Peter
#1817812
Lesenswert?

Frank M. schrieb:
> Ich habe schon erlebt, dass hier eine if-else-if-Kette
> mit Or-Verknüpfung statt der Mehrfach-Cases wesentlich kleineren Code
> erzeugt.

Ich habe immer nur das Gegenteil erlebt.
Beim Switch versucht er nämlich, ähnlichen Code von Cases zusammen zu 
fassen.
Man sieht eigentlich immer, daß er in andere Cases hineinspringt, obwohl 
das nicht so im Code steht.

Bei if/else läuft aber alles nacheinander ab und daher kann er nicht 
mehr ähnlichen Code mehrfach nutzen.


Peter
#1818585
Lesenswert?

Samuel K. schrieb:
> Aber wenn ich die letzte Zeile als
> Compiler Flag einsetze kommt ein Linker Error, dass er meine 2
> Funktionen in main nicht findet.

Diese Flags darfst du nur verwenden, wenn dein Projekt entweder nur aus 
einer einzigen Sourcedatei besteht, oder wenn alle Sourcen mit einem 
einzigen Compileraufruf in einem Rutsch kompiliert und gelinkt werden. 
Letzteres wird wohl in deinem Makefiles nicht gemacht (ist auch eher 
selten der Fall), deshalb kannst du die Flags so nicht verwenden.

Andreas

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren