Optimierung mit/ohne volatile

OP #4657831
Hallo Leute,
bis jetzt glaubte ich mit "volatile" mehr oder weniger sattelfest zu 
sein, aber das folgende hat mich doch verblüfft.

Ich habe ein Spartan-6 Design mit Microblaze und selbsgeschriebenem IP 
core, der einen 64 KB Speicherbereich andeckt.
In diesem Speicherbereich liegen 2 Tabellen zu 16 Worten (32 Bit), an 
den Offsets 0x100 und 0x140.
1
static const uint32_t MNTable_AB_offset  = 0x00000100;
2
static const uint32_t MNTable_CD_offset  = 0x00000140;
3

4
#define MNTable_AB            (uint32_t *) (XPAR_PRINTCORE_IF_BASEADDR + MNTable_AB_offset)
5
#define MNTable_CD            (uint32_t *) (XPAR_PRINTCORE_IF_BASEADDR + MNTable_CD_offset)
Eine Funktion
1
int scanWaveFormForMNs(uint16_t *waveform, int waveformlength, volatile uint32_t *mdtable, unsigned int mdtable_size, uint16_t offset)
2
{
3
    int i, count = 0;
4
    uint32_t mn;
5
    uint8_t mn_old = 0;
6

7
    for (i = 0; i < waveformlength; i++) {
8
        if ((*waveform++ & 0xF000) == 0xF000) {
9
            mn = (*waveform++ & 0xF000) >> 8;
10
            mn |= (*waveform++ & 0xF000) >> 12;
11
            if (mn != mn_old) {
12
              unsigned ii = i;
13
              mn_old = mn;
14
              mn <<= 10;
15
              ii += i != 0 ? offset : 0;
16
              mn |= ii & 0x3FF;
17
              mn |= 0xF0000000;
18
                mdtable[count] = mn;
19
                xil_printf("md[%d] = %x, rb = %x", count, mn, mdtable[count]);
20
                count++;
21
            }
22
            i += 2;
23
        }
24
    }
25
    return count;
26
}
füllt diese Tabellen.
Man muss jetzt nicht verstehen, was die Funktion berechnet, aber an der 
Stelle
mdtable[count] = mn;
sollte die Tabelle, und somit auch das IP beschrieben werden.

Der Aufruf schaut so aus:
1
scanWaveFormForMNs((uint16_t *) Kom_Buffer, WaveformLength, MNTable_AB, MNTableSize, 8-3);

Lässt man das volatile in
1
int scanWaveFormForMNs(uint16_t *waveform, int waveformlength, volatile uint32_t *mdtable, unsigned int mdtable_size, uint16_t offset)
weg, funktioniert das Ganze nicht, der Zugriff auf die Tabelle im IP 
wird nicht ausgeführt.
Man merkt dies auch daran, weil die höchsten 8 Bits in Hardware nicht 
existieren, und beim Zurücklesen mit mdtable[count] mit Nullen gefüllt 
werden.
Ohne volatile wird z.B. 0xF0000400 zurückgelesen, mit volatile 
korrekterweise 0x400.

Wieso können beim Optimieren einer Funktion Schreibzugriffe auf eine zu 
füllende Tabelle wegoptimiert werden?
Die Optimierung der Funktion kann ja nicht wissen, was im Rest des 
Programms mit diesen Daten passiert?

Optimierungsstufe ist O3.
Gast
Bei zugriffen auf Hardware Register ist volatile Pflicht.

Ansonsten geht so etwas auch in die Hose
1
PORTA |= (1<<0);
2
PORTA |= (1<<1);
wenn der Compiler anfängt zu optimieren macht er nur ein Read Modify 
Write, anstatt 2.
Gast
Klaus F. schrieb:
> Man merkt dies auch daran, weil die höchsten 8 Bits in Hardware nicht
> existieren, und beim Zurücklesen mit mdtable[count] mit Nullen gefüllt
> werden.

warum sollte er auch ohne volatile die Daten aus mdtable[count] lesen?
1
mdtable[count] = mn;
2
xil_printf("md[%d] = %x, rb = %x", count, mn, mdtable[count]);

er macht einfach
1
mdtable[count] = mn;
2
xil_printf("md[%d] = %x, rb = %x", count, mn, mn);

daraus. Was für den Compiler das gleiche ergeben muss.
OP
Ok, ich habe es wahrscheinlich nicht gut erklärt.
Das printf ist erst nachträglich dazugekommen, weil der IP Core nicht 
korrekt funktioniert hat.
Dass im printf der falsche, optimierte Wert ausgegeben ist erklärbar, 
das stimmt.
Warum die Register des IP Core aber nur mit "volatile uint32_t *mdtable" 
korrekt gefüllt werden, ist für mich nicht erklärbar.
Für die Funktion ist eine Tabelle die gefüllt werden muss.
Ob der Speicher, auf den der Zeiger zeigt im RAM steht oder im IP Core 
kann die Funktion nicht wissen.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 10 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.