PIC32 ASM atomic Funktionen

Gast #3288818
Lesenswert?

Hi,

ich brauche für ein Projekt ein paar Funktionen die mir Flags setzen und 
löschen können sollen und das auch bei globalen Variablen (INT-Vars).

Bis jetzt hatte ich einfach die INTs zwischen drin deaktiviert und die 
Sachen bearbeitet.
Aber auf dauer ist das sehr umständlich.

So, jetzt habe ich mir ein paar Funktionen geschrieben die ohne 
deaktivierung der INTs auskommen sollen.
Könntet Ihre euch die mal ansehen ob das so in Ordnung sind oder ob ich 
da noch Fehler drin habe.

Optimierungsvorschläge sind auch willkommen. ;-)

PS: ist mein erstes mal mit dem PIC ASM also bitte etwas nachsicht.

Stephan
Angehängte Dateien:
Gast #3288928
Lesenswert?

durch die Befehle 'LL' und 'SC'.

LL - merkt sich beim lesen die Speicherstelle und wenn der Wert wieder 
geschrieben wird, durch SC, funktioniert das nur, wenn die 
Speicherstelle nicht verändert worden ist.
#3289352
Lesenswert?

Ohne besondere Maßnahmen (Interruptsperre) ist alles, was länger als ein 
Assembler-Befehl ist, nicht atomar.
Ob man es in C oder Assembler schreibt, ist egal.

Bei RISC-CPUs würde ich mir deshalb eine Art Präfixbefehl wünschen: "DI 
5" (Führe die folgenden 5 Befehle unter Interruptsperre aus).
#3289361
Lesenswert?

> Bei RISC-CPUs würde ich mir deshalb eine Art Präfixbefehl wünschen:
> "DI 5" (Führe die folgenden 5 Befehle unter Interruptsperre aus).


PIC24 und dsPIC33 haben sowas:

DISI Disable Interrupts Temporarily
Syntax: {label:} DISI #lit14
Operands: lit14  [0 ... 16383]
Operation: lit14 → DISICNT
1 → DISI
Disable interrupts for (lit14 + 1) cycles
Status Affected: None

PIC32 kenn ich (noch) nicht.
#3289370
Lesenswert?

Stephan schrieb:
> Könntet Ihre euch die mal ansehen ob das so in Ordnung sind oder ob ich
> da noch Fehler drin habe.

Bin mit MIPs nicht vertraut. Üblicherweise gibts aber Beispielcode, 
nicht zuletzt vom Hersteller (Microchip oder MIPS).

Da Microchips Compiler aber GCC ist scheint mir der Rückgriff auf 
Assembler unnötig. Oft gibts für solche Spezialbefehle irgendwo inline 
Pseudo-Funktionen, so dass man in C bleiben kann.
Gast #3289371
Lesenswert?

Peter Dannegger schrieb:
> Ohne besondere Maßnahmen (Interruptsperre) ist alles, was länger als ein
> Assembler-Befehl ist, nicht atomar.

Aber bei manchen Prozessoren gibt es geeignete Befehle in der Art Test 
and Set, die ein Bit atomar lesen und dann setzen, damit lassen sich 
einige Aufgaben lösen. Ob es sowas bei PIC32 gibt weiss ich nicht.

Beim guten alten Z80 konnte man mit einem Befehl ein Byte im Speicher 
decrementieren und dabei die Flags setzen. Kann man für Semaphore usw. 
brauchen.

Gruss Reinhard
#3289375
Lesenswert?

A. K. schrieb:
> Der Trick besteht darin, dass die Kollision mit
> Interrupts oder anderen Busmastern erkannt wird und zur Neuversuch
> führt.

Klingt sehr kompliziert.
Heißt das, die CPU merkt sich die LL-Zeile und wenn vor SC ein Interrupt 
erfolgt, führt sie allen Code ab LL nochmal aus?

Heißt das auch, LL/SC müssen genau paarweise erfolgen?
Und sind mehrere LL/SC geschachtelt möglich?
#3289376
Lesenswert?

Reinhard Kern schrieb:
> Aber bei manchen Prozessoren gibt es geeignete Befehle in der Art Test
> and Set, die ein Bit atomar lesen und dann setzen, damit lassen sich
> einige Aufgaben lösen. Ob es sowas bei PIC32 gibt weiss ich nicht.

Da es LL/SC gibt offensichtlich nicht. TAS oder LOCK XCHG (x86) sind 
aufgrund ihrer Ineffizienz etwas aus der Mode gekommen. Solche LL/SC 
sind wesentlich effizienter.
#3289383
Lesenswert?

Peter Dannegger schrieb:
> Heißt das, die CPU merkt sich die LL-Zeile und wenn vor SC ein Interrupt
> erfolgt, führt sie allen Code ab LL nochmal aus?

Ich beschreibe es mal ungefähr so, wie ich es von PowerPC und neueren 
ARMs her kenne: Die CPU läd in LL ein Wort aus dem Speicher und merkt 
sich die Adresse des Wortes in einem speziellen Register. Wenn dieser 
Wert bei SC noch übereinstimmt, dann wird ein Wort dort abgespeichert, 
sonst nicht. Zusätzlich wird dieser Status als Ergebnis von SC irgendwo 
abgelegt.

In Interrupts kann nun dieses Register gelöscht werden, wenn sinnvoll. 
Bei externen Buszyklen (anderer Core, anderer Busmaster), die auf 
ebendiese Adresse zugreifen, geschieht es automatisch.

Wenn also der Code beim SC Befehl merkt, dass etwas dazwischen kam, dann 
probiert der Code den Kram einfach nochmal. Also nicht der Processor, 
sondern das Programm. Siehe oben, im direkt auf SC folgenden bedingten 
Sprung.

Vorteil: Diese Befehle sind sehr einfache Befehle, die im Normalfall 
schnell durchlaufen und keine besonderen und teuren Buszyklen erfordern.

> Heißt das auch, LL/SC müssen genau paarweise erfolgen?

So ist es gedacht. Man sollte sich das ggf. im Handbuch genau nachlesen, 
oft gibt es bestimmte Voraussetzungen und Randbedingungen.

> Und sind mehrere LL/SC geschachtelt möglich?

Nein. Wüsste auch nicht, was das hier brächte.

Wenn dir das zu einfach ist und du es gerne etwas komplexer hast, dann 
schau dir mal Intels Befehlserweiterung in Haswell an, der Support für 
Transactional Memory. David Kanter hat das auf 
http://www.realworldtech.com/ gut beschrieben.
#3289451
Lesenswert?

Peter Dannegger schrieb:
> Ein DISI x fände ich allerdings einfacher.

Ist in Assembler recht nett.

Für die heute dominierende Umsetzung in Hochsprache ist es allerdings 
ziemlich unpraktisch, setzt es doch eine entsprechende Compilermimik 
voraus. Sowas wie
  __run_with_irqs_disabled { code ... }

Zilog hat in den eZ8 auch sowas in Art drin - aber dank geradezu 
klassischer Konstrukteur/Entwickler-Schere keinen entsprechenden Support 
im eigenen Compiler.
Gast #3289507
Lesenswert?

Peter Dannegger schrieb:
> Ein DISI x fände ich allerdings einfacher.
> Und da Interrupts eh immer ein Gedöns an Prolog/Epilog haben, sind mal 5
> Zyklen Sperre nicht von Bedeutu
> Ein DISI x fände ich allerdings einfacher.
> Und da Interrupts eh immer ein Gedöns an Prolog/Epilog haben, sind mal 5
> Zyklen Sperre nicht von Bedeutung.ng.

Code und Kommentar aus einem Manual für PIC24 kopiert, weiß nicht mehr 
aus welchem (benutze nur C):
1
void EepErase(void) {
2
    NVMCON = 0x4050;            // Set up NVMCON to bulk erase the data EEPROM
3
    asm volatile ("disi #5");   // Disable Interrupts For 5 Instructions
4
    __builtin_write_NVM();      // Issue Unlock Sequence and Start Erase Cycle
5
    while(_WR)
6
        ;
7
}

MfG Klaus
#3289642
Lesenswert?

yup, dass gibt es mit gcc schon frei haus fuer mips/arm und andere,
auch im gcc des xc32 scheint es enabled zu sein. also auch ohne 
assembler oder _ASM_ in c/c++ nutzbar.

siehe gcc doc: Atomic-Builtins

37:                  result = __sync_add_and_fetch(&safecounter, 1);

9D001054  0000000F   SYNC
9D001058  C3828014   LL V0, -32748(GP)
9D00105C  24410001   ADDIU AT, V0, 1
9D001060  E3818014   SC AT, -32748(GP)
9D001064  1020FFFC   BEQ AT, ZERO, 0x9D001058
9D001068  24420001   ADDIU V0, V0, 1
9D00106C  0000000F   SYNC
9D001070  AF828018   SW V0, -32744(GP)
Gast #3289825
Lesenswert?

Peter Dannegger schrieb:
> Ein DISI x fände ich allerdings einfacher.
> Und da Interrupts eh immer ein Gedöns an Prolog/Epilog haben, sind mal 5
> Zyklen Sperre nicht von Bedeutung.

Wenn ich es richtig verstehe, funktioniert LL/SC nicht nur für 
Interrupts, sondern auch für mehrere Busmaster. Letzteres kann DISI 
nicht abfangen.
Gast #3293127
Lesenswert?

>LL - merkt sich beim lesen die Speicherstelle und wenn der Wert wieder
>geschrieben wird, durch SC, funktioniert das nur, wenn die
>Speicherstelle nicht verändert worden ist.
LL-SC ist als atomic Ersatz witzlos, da im Falle des veränderten 
Mem-Wertes doch wieder zusätzlicher Code (mit zus. Takten) erforderlich 
ist.


>Aber bei manchen Prozessoren gibt es geeignete Befehle in der Art Test
>and Set, die ein Bit atomar lesen und dann setzen,...
sind schon CISC-Befehle (RMW), die typ. RISCs nicht haben.

>PIC24 und dsPIC33 haben sowas:
>DISI Disable Interrupts Temporarily
PIC24 kann oft darauf verzichten, da der versch. CISC-Befehle hat.
(sofern 8kB-Bereich)
#3293202
Lesenswert?

MCUA schrieb:
> LL-SC ist als atomic Ersatz witzlos, da im Falle des veränderten
> Mem-Wertes doch wieder zusätzlicher Code (mit zus. Takten) erforderlich
> ist.

Warum es deshalb witzlos?

Es ist übrigens kein zusätzlicher Code, sondern der gleich wie beim 
vorherigen Versucht, als Schleife. Voraussetzung ist natürlich, dass man 
mit einer nichtdeterministischen Laufzeit der Sequenz leben kann.

Aber wie ich oben schon andeutete: Diese Methode adressierte 
ursprünglich Multiprocessing. Die Verwendbarkeit auf Singlecores als 
Ersatz atomarer Operationen ist eher ein Nebenffekt. Wer damit nichts 
anfangen kann, dem bleibt es unbenommen, in traditioneller Weise die 
Interrupts abzuschalten.
Gast #3293246
Lesenswert?

A. K. schrieb:
> in traditioneller Weise die
> Interrupts abzuschalten.

Ich sehe auch nicht, wieso eigentlich ein Pärchen DI..EI so unzumutbar 
viel Aufwand sein soll und die Performance beeinträchtigt. Das Problem 
ist höchstens, dass man es vergisst, aber das gilt für alles andere 
auch, des Problems atomarer Operationen muss man sich bewusst sein, oder 
man kann eben nicht programmieren. Natürlich darf man zwischen DI und EI 
nur das absolut notwendige durchführen und nicht eine 
Differentialgleichung lösen.

Gruss Reinhard
#3293273
Lesenswert?

Reinhard Kern schrieb:
> Ich sehe auch nicht, wieso eigentlich ein Pärchen DI..EI so unzumutbar
> viel Aufwand sein soll und die Performance beeinträchtigt.

Tut es auch nicht, die paar Takte abgeschalteten Interrupts sind 
meistens kein Problem. Es gibt eben beide Wege. Jeder Weg hat seine 
Vorteile. Der hier betrachtete ist freilich vielen Leuten unbekannt, was 
leicht zu dem "kenn ich nicht, also mag ich es nicht" Effekt führt.

Ein bedeutender Unterschied entsteht freilich dann, wenn man nicht mehr 
mit universellen Rechten programmiert. Denn wenn es überhaupt 
Privilegstufen gibt (z.B. ARM7, Cortex-M), dann sind DI/EI privilegiert. 
LL/SC artige Operationen stehen jedoch auch nichtpriviligierten 
Programmen zur Verfügung.

Dass die Cortex-M3/4 und PIC32 Microcontroller solche Operationen 
überhaupt haben liegt daran, dass diese Cores universell gebaut sind und 
ggf. auch in Mehrprozessorsystemen einsetzbar sein sollen.
Gast #3293461
Lesenswert?

A. K. schrieb:
> Der hier betrachtete ist freilich vielen Leuten unbekannt, was
> leicht zu dem "kenn ich nicht, also mag ich es nicht" Effekt führt.
Ja da kenne ich genügend Leute..... ;-)

> Ein bedeutender Unterschied entsteht freilich dann, wenn man nicht mehr
> mit universellen Rechten programmiert. Denn wenn es überhaupt
> Privilegstufen gibt (z.B. ARM7, Cortex-M), dann sind DI/EI privilegiert.
> LL/SC artige Operationen stehen jedoch auch nichtpriviligierten
> Programmen zur Verfügung.
das ist gut. kannte ich auch noch nicht.

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