Forum: Mikrocontroller und Digitale Elektronik Atmel AVR: Befehl CPSE


von senex24 (Gast)


Lesenswert?

Compare  Skip if Equal

Der Befehl muss wohl wichtig sein, sonst wäre er nicht in einem
reduzierten Befehlssatz zu finden. Da ich ihn aber nur selten benutze,
habe ich wahrscheinlich etwas nicht verstanden. Wer hilft mir auf die
Sprünge?

von Dirk (Gast)


Lesenswert?

Hi,

kein Woerterbuch zu Hause oder wo ist das Problem?

Compare  Skip if Equal

Vergleiche überspringe wenn gleich.

Gruß,
Dirk

von johnny.m (Gast)


Lesenswert?

Der Befehl vergleicht zwei Register, und wenn beide den selben Wert
haben, wird der nächste Befehl übersprungen...

von Mathias (Gast)


Lesenswert?

im prinzip ist es das gleiche wie ein if in c!

von tastendrücker (Gast)


Lesenswert?

> Da ich ihn aber nur selten benutze, habe ich wahrscheinlich etwas
> nicht verstanden.

Na, wenn du ihn schon benutzt, dann weisst du doch wozu er gut ist?!?
Wo ist dein Problem?

von Simon K. (simon) Benutzerseite


Lesenswert?

@Mathias, naja, nicht so ganz.


Das Equivalent zu
1
if (A != B) C = C - 5;
2
D = C

wäre
1
cpse A, B
2
subi C, 5
3
out D, C

von Simon K. (simon) Benutzerseite


Lesenswert?

PS: Der Compiler erzeugt natürlich was anderes. Ist jetzt nur so ein
Gedankenkonstrukt.

von senex24 (Gast)


Lesenswert?

Ich vermutete eine herausragende Bedeutung des Befehls, zumal ja auch im
Gegensatz zu den anderen Compares die Flags nicht geändert werden.
Normalerweise hat in einem RISC-Befehlssatz jeder Befehl seinen
gewichtigen Grund.

von johnny.m (Gast)


Lesenswert?

Naja, man kann ja mal überlegen, wie oft so ein Vergleich vorkommt. Und
wenn man den mit einem Befehl erschlagen kann, ist das sicher
wünschenswert. Zumal die AVRs extra für Hochsprachen-Programmierung
optimiert sind. Simons Beispiel mit dem if ist ein Konstrukt, das sehr
häufig ist und bei dem es sinnvoll sein kann, es möglichst effizient zu
implementieren

von A.K. (Gast)


Lesenswert?

Mir ist bislang auch noch kein Beipiel eingefallen, in dem CPSE mehr
einspart als einen nicht ausgeführten bedingten Sprung, also 1 Takt.
Diese Einsparung kommt in Schleifen wie in memchr() zum Tragen, die
zwei Abbruchbedingungen enthalten
(http://www.mikrocontroller.net/forum/read-1-167735.html#167786,
http://www.mikrocontroller.net/forum/read-1-182869.html#182875).

Vielleicht gibt es ja einen wichtigen Controller-Benchmark, der sich
damit ein bischen beschleunigen liess. Sonderlich teuer ist die
Implementierung nicht.

von senex24 (Gast)


Lesenswert?

Teuer wohl nicht, aber man hätte mit dem Bitmuster etwas anderes machen
können, z.B. stolpere ich regelmäßig darüber, dass LDI und CPI nur mit
r16..r31 arbeiten, während dieses CPSE alle Register zuläßt.

von Läubi (Gast)


Lesenswert?

ALLE Register register befhle könne alle register ansprechen (wäre ja
sonst blöd)
Imidiate Befehle gehen nur auf den unteren registern, weil sont der
imidiate Wert nichtmehr reinpasst!
CPSE ist ein sehr wichtiger Befhel weil er ATOMAR arbeitet, das heißt
folgendes:

cpi temp, 100
brne woandershin

kann in der mitte unterbrochen werden durch einen Interupt!!
CPSE aber nicht weils ein Befehl ist!
Dies sit besonders wichtig bei geschared recourcen, wo eine bestimmte
Programmsektion nur betreten werden darf wenn ein bestimmter Wert
(meistens 0) in einem register gibt (Stichwort counting semaphore im
zusammenhang mit Reader Writer Problem und reader preference), bei den
meisten Prozessoren gibt es einen SKIP IF ZERO Befehl für genau diesen
einsatzzweck!

Der Befehl ist deshalb eigentlich sehr wichtig, damit man geschüzte
Bereiche erstellen kann ohne bei jedem test die golbalen Interupt
komplett ausschalten zu müssen.

Der Befehl ist von daher sogar sehr wichtig auch wenn man (meist)

von Läubi (Gast)


Lesenswert?

es nicht nuzt (fehlt da noch :D
Ich bin zu müde :P

von Rolf Magnus (Gast)


Lesenswert?

> Teuer wohl nicht, aber man hätte mit dem Bitmuster etwas anderes
> machen können, z.B. stolpere ich regelmäßig darüber, dass LDI und
>  CPI nur mit r16..r31 arbeiten, während dieses CPSE alle Register
> zuläßt.

Um hier noch r0 bis r15 zu unterstützen, bräuchte man aber viiiiiiiel
mehr Platz im Befehlsraum. Du mußt dir überlegen, daß ein Befehl 16 bit
breit ist. LDI und CPI bekommen jeweils einen Immediate-Wert mit, für
den schon mal 8 Bit, also die Hälfte drauf geht. Bei 32 Registern
bräuchte die Nummer des Registers nochmals 5 Bits. Dann wären gerade
mal drei Bits für den Opcode übrig. Bei 16 Bits gibt es insgesamt 65536
mögliche Bitkombinationen (die nenne ich mal den Befehlsraum). Ein LDI,
das alle Register ansprechen könnte, bräuchte davon alleine für sich
schon ein Achtel. CPI nochmals. Dann gibt's ja auch noch SUBI, SBCI,
ANDI und ORI. Damit würden diese 6 Befehle drei Viertel des gesamten
Befehlsraumes brauchen. Es wäre einfach kein Platz mehr für all die
anderen Befehle, die noch gebraucht werden. Deshalb hat man die Zahl
der Register, mit denen sie benutzt werden, halbiert und damit ein Bit
mehr für den Opcode rausbekommen. Die Befehle brauchen so nur noch drei
Achtel des Befehlsraums.
CPSE bekommt nur zwei Register, von denen für jedes fünf Bits benötigt
werden. Es sind also noch sechs Bits für den Opcode übrig. Damit belegt
dieser Befehl nur 1/64 des Befehlsraums und ist verglichen mit einem LDI
deutlich leichtgewichtiger.

von A.K. (Gast)


Lesenswert?

"weil er ATOMAR arbeitet"

Jo, aber erklär mir, was es bringt, den Compare und seinen Sprung
ununterbrechbar zu machen. Kann ich grad nicht nachvollziehen. Ergibt
für mich erst einen Sinn, wenn auch der auf CPSE folgende Befehl noch
garantiert ununterbrechbar mitläuft. Sowas wie:
  cpse r1,r2
  inc  r1

So koppeln denn auch alle Sema-Operationen, denen ich bislang begegnet
bin, Test und Modifikation (test-and-set, compare-and-add, usw), oder
sie ermöglichen es, das iterativ abzuwickeln
(load-and-reserve/store-conditional).

von Frank E. (erdi-soft)


Lesenswert?

Auch die sogenannten Test-and-Set-Befehle arbeiten atomar.

Stell dir vor, du überprüfst eine Variable auf ihren Wert. Jetzt kommt
vor dem Sprungbefehl ein Interrupt (oder machen wir es einfacher, es
findet ein Threadwechsel statt). Dieser überprüft die Variable,
verändert sie und gibt den Prozessor wieder ab.
Jetzt hat dein alter Thread das Problem, dass die Variable verändert
wurde, er das aber nicht merkt und nach seiner vorherigen Überprüfung
weitergeht.
Kino, Sitzplatzreservierung. Der erste Thread überprüft, ob der Sitz
noch frei ist. Vor dem Sprung kommt der andere Thread, überprüft
zufälligerweise den selben Sitz, reserviert ihn und gibt die Kontrolle
ab. Nun reserviert der alte Thread den Sitz ebenfalls, da er nicht
weiß, dass der andere das schon getan hat.

von Frank E. (erdi-soft)


Lesenswert?

Hmmm, wie immer gilt, erst denken, dann schreiben.

@A.K.: Jetzt ist klar, was du meinst. Ist schon spät und mein Kopf
brummt schon wegen dieser dooofen Betriebssystem-Klausur.

von A.K. (Gast)


Lesenswert?

War das jetzt einen Antwort an mich? Die Verwendung der test-and-set
Varianten ist mir durchaus bekannt. Neu ist mir freilich, dass man mit
compare-and-branch das gleiche erreichen kann. Beispiel bitte.

von Peter D. (peda)


Lesenswert?

"Atomar" ist beim Vergleich völlig schnurz.

Atomar hat nur Bedeutung bei Read-Modify-Write Zugriffen.
Ob CP oder CPSE ist also völlig egal, da ja nichts zurück geschrieben
wird.

Und außerdem sind Zugriffe auf mehrere Bytes (16 oder 32 Bit) auf
8-Bittern per default nicht atomar.


Ich finde CPSE auch nicht sonderlich nützlich.
Ein EORI wäre wesentlich sinnvoller gewesen. So muß man jedesmal erst
ein Register laden, um Bits zu kippen.


Das mit den unteren Registern hätte man einfach dadurch lösen können,
daß diese dann mit 2-Wort-Befehlen auch Konstanten verarbeiten können.


Peter

von Bernhard S. (bernhard)


Lesenswert?

Was ist eigentlich "Atomar" ? Was wäre das Gegenstück dazu?


Bernhard

von A.K. (Gast)


Lesenswert?

Vor hundert Jahren galt das Atom noch als kleinste unteilbare Einheit.
Daraus leitet sich der Begriff "atomar" für unteilbare Dinge ab. Das
ergibt zwar seit Meissner/Hahn vor ~70 Jahren keinen Sinn mehr, aber da
war's schon zu spät und die Bedeutung steckte in der Sprache drin.
Selbst in einer Wissenschaft, die deutlich jünger ist.

Heisst in diesem Zusammenhang also, dass die einzelnen Teiloperationen
einer atomaren Befehlssequenz nicht von Interrupts unterbrochen werden
können. Je nach System kann sich das auch auf nicht einem anderen
Busmaster unterbrechbare Busoperationen beziehen.

von A.K. (Gast)


Lesenswert?

Korrektur: s/Meissner/Meitner/

von Michael Wilhelm (Gast)


Lesenswert?

Atomar bedeutet nicht unterbrechbar durch z. B. Interrupts.

MW

von Frank E. (erdi-soft)


Lesenswert?

@A.K.: Ich meinte damit, ICH sollte erst denken, dann schreiben. :-)

von Rolf Magnus (Gast)


Lesenswert?

> Vor hundert Jahren galt das Atom noch als kleinste unteilbare
> Einheit. Daraus leitet sich der Begriff "atomar" für unteilbare
> Dinge ab.

Eigentlich ist es genau umgekehrt. Das Atom wurde nach dem griechischen
Wort "atomos" (=unteilbar) benannt. Der Begriff "atomar" ist also
eigentlich korrekt. Es ist vielmehr das Atom, das seinen Namen zu
unrecht hat.

von Bernhard S. (bernhard)


Lesenswert?

@A.K.

>Heisst in diesem Zusammenhang also, dass die einzelnen
>Teiloperationen einer atomaren Befehlssequenz nicht von Interrupts
>unterbrochen werden können. Je nach System kann sich das auch auf
>nicht einem anderen Busmaster unterbrechbare Busoperationen beziehen.

Gut erklärt :)

Ich vermute, dass folgender Befehl auch atomar ist?

add R1, R2       ; zwei Register addieren


Welcher Befehl wäre für einen ATmegaxx nicht atomar?

Bernhard

von Simon K. (simon) Benutzerseite


Lesenswert?

einzelne Befehle sind immer atomar, denn während eines Befehlsablauf,
wird der Controller nie in einen Interrupt springen. Höchstens zwischen
zwei Befehlen.

Ein Beispiel für eine nicht atomare sache ist ein ganz normaler Branch
Befehl (Beispiel von Läubi):
1
cpi temp, 100
2
brne woandershin

Dieses Konstrukt ist nicht atomar, da es unterbrochen werden kann.

PS: man kann die ganze Suppe aber doch wieder mit cli/sei atomar
machen. Ist dann halt ein atomarer Block, der mehrere Taktzyklen
dauert, aber ist ja egal.

von A.K. (Gast)


Lesenswert?

"Höchstens zwischen zwei Befehlen."

Nö. Es gibt etliche Architekturen, in denen innerhalb eines
Einzelbefehls unterbrochen werden kann.

Das betrifft einerseits regelmässig Blocktransferbefehle (z.B. Z80,
x86), da die Interrupt-Latenz sonst exorbitante Werte annehmen würde.
Die können zwischen den Interationen unterbrochen werden und setzen
danach automatisch wieder an der richtigen auf.

Es gibt aber auch Implementierungen, bei denen ein ganz normal
wirkender Befehl unterbrochen werden kann. Mir bekannt bei diversen
Modelle der 68000-Reihe, ab 68010. Bei Speicherzugriffsproblemen wird
dort der Ablauf vom Microcode unterbrochen und ggf. wieder aufgesetzt,
d.h. da wird mitten drin im Befehlsablauf unterbrochen.

Die eleganteste Variante atomarer Befehle findet sich in eZ8: Da gibt
es einen Befehl, der die folgenden 3 Befehle zu einer atomaren Sequenz
zusammenfasst.

von Simon K. (simon) Benutzerseite


Lesenswert?

Danke A.K.

von Peter D. (peda)


Lesenswert?

"Ein Beispiel für eine nicht atomare sache ist ein ganz normaler Branch
Befehl (Beispiel von Läubi):"


Wie schon gesagt, das ist Quatsch mit Soße. Wenn zwischen CPI und BRNE
ein Interrupt kommt, passiert genau absolut garnichts, d.h. der Sprung
wird überhaupt nicht beeinflußt.


Mit "nicht atomar" meint man nur Sachen, bei denen es auch darauf
ankommt und die man dann durch Klammerung mit cli+sei atomar machen
muß.


Ein Beispiel ist das Lesen von 16Bit-Werten:

[ARVASM]
lds r16, myval_lo
lds r17, myval_hi
[/AVRASM]

Wenn nun ein Interrupt dazwischenhaut und my_val ändert, dann hat man
ein altes und ein neues Byte und der Wert ist falsch.

Z.B. der Interrupt zählt myval hoch:
...
0x01FE
0x01FF
0x02FF <- falsch !!!
0x0200
0x0201
...

Peter

von johnny.m (Gast)


Lesenswert?

> ...d.h. der Sprung wird überhaupt nicht beeinflußt...
Er wird nur dann nicht beeinflusst, wenn das SREG im Interrupt Handler
ordnungsgemäß gesichert und am Ende wieder geladen wird. Sonst gehts
schief...

von Simon K. (simon) Benutzerseite


Lesenswert?

Genau, so wie johnny.m es sagt, habe ich auch gedacht.

PS: Sogesehen hast du dann natürlich völlig Recht, Peter!

von Hagen R. (hagen)


Lesenswert?

Hmn, aber denoch ist die Zeit in Takten die zwischen
1
cpi temp, 100
2
brne woandershin

vergeht auf Grund dessen das sie nicht mehr atomar sind nicht mehr
vorhersagbar wenn man im Interrupts arbeitet. Atomar macht für mich als
Ausssage doch nur Sinn wenn ich bei der Manipulation von Thread/IRQ
übergreifenden Daten, also gemeinsam benutzt, ohne ein CLI/STI
auskommen möchte.

Gruß Hagen

von Peter D. (peda)


Lesenswert?

Wer in Interrupts das SREG nicht sichert, wird kaum lauffähige Programme
heraus bekommen.
Und wenn doch, dann sind diese nur schwer wartbar und erweiterbar.

Gewisse Grundlagen sollte man schon als selbsverständlich voraussetzen
können.

Warum die AVR-Entwickler das SREG nicht automatisch sichern, ist mir
völlig schleierhaft. Es gibt Architekturen, die können das.


Peter

von Xenu (Gast)


Lesenswert?

>Wer in Interrupts das SREG nicht sichert, wird kaum lauffähige
>Programme heraus bekommen.

So'n Quatsch. Dann müssten die meisten meiner Programme nicht laufen.
Tun sie aber und ganz prächtig sogar.
Wenn es nicht nötig ist, warum soll man es dann tun?

>Und wenn doch, dann sind diese nur schwer wartbar und erweiterbar.

Warten muss man Programme nur, wenn sie nicht funktionieren.
Und wieso soll man sie nicht erweitern können?

>Warum die AVR-Entwickler das SREG nicht automatisch sichern, ist mir
>völlig schleierhaft.

Mir nicht. Es nicht unbedingt nötig. Und wenn es automatisch gesichert
würde, würden die Interruptroutinen mehr Takte benötigen.
Und wenn Du es sichern willst, kannst Du das ja tun.

>Es gibt Architekturen, die können das.

Freilich gibt es die. Es gibt auch Controller, die haben eine
Gleitkommaeinheit eingebaut.

von johnny.m (Gast)


Lesenswert?

@Xenu:
Wenn Deine Programme alle funktionieren, ohne dass Du in
Interrupt-Handlern das SREG sicherst, dann arbeitest Du entweder ohne
Verzweigungsbefehle oder es ist Zufall (Ich vermute eher das zweite)!
Wenn Du natürlich exzessiv mit cli/sei arbeitest, dann OK, aber der
Code-Aufwand dürfte in den meisten Fällen ungleich höher sein. Klar,
die Wahrscheinlichkeit, dass ein Interrupt bei einer (z.B.)
cpX-brYY-Kombination dazwischenhaut ist nicht sehr hoch und dass in der
ISR dann auch noch gerade die benötigten Flags verändert werden, auch
nicht, aber über längere Zeit gesehen ist es sicher nicht mehr
zuverlässig!

von Rolf Magnus (Gast)


Lesenswert?

>>Wer in Interrupts das SREG nicht sichert, wird kaum lauffähige
>>Programme heraus bekommen.
>
> So'n Quatsch. Dann müssten die meisten meiner Programme nicht
> laufen.
> Tun sie aber und ganz prächtig sogar.
> Wenn es nicht nötig ist, warum soll man es dann tun?

Wenn es nicht nötig ist (also die Interrupt-Routine das SREG nicht
verändert), hat man ja auch keine Probleme, wenn man es nicht sichert.
Das kommt zumindest bei mir aber sehr selten vor.

>>Und wenn doch, dann sind diese nur schwer wartbar und erweiterbar.
>
> Warten muss man Programme nur, wenn sie nicht funktionieren.

Oder wenn man sie ändern oder Teile davon in einem neuen Programm
weiterverwenden möchte.

>Warum die AVR-Entwickler das SREG nicht automatisch sichern, ist mir
>völlig schleierhaft.

> Mir nicht. Es nicht unbedingt nötig. Und wenn es automatisch
> gesichert würde, würden die Interruptroutinen mehr Takte
> benötigen.
> Und wenn Du es sichern willst, kannst Du das ja tun.

Allerdings braucht das noch mehr Takte, da man das SREG nicht direkt,
sondern nur über den Umweg eines Registers auf den Stack bekommt.

von Simon K. (simon) Benutzerseite


Lesenswert?

Xenu hat recht, es gibt doch Befehle, die das SREG nicht beeinflussen.
Wenn man nur solche in der Interruptroutine hat, brauch man das SREG
doch auch nicht sichern....

von Xenu (Gast)


Lesenswert?

>(Ich vermute eher das zweite)

Falsch vermutet.

von johnny.m (Gast)


Lesenswert?

Ach, Du arbeitest ohne Verzweigungsbefehle?

von crazy horse (Gast)


Lesenswert?

Verzweigungsbefehle sind das eine, dazu kommen auch noch
Arithmetik/Logik aller Art, wenn sie über mehr als ein Byte gehen, dazu
werden auch die Flags gebraucht.
Bei mir gibt es kaum Interruptprogramme, in denen das SREG nicht
verändert wird, allzuviele sinnvolle Anwendungen kann ich mir auch gar
nicht vorstellen. Deshalb sichere ich es erst mal grundsätzlich, sollte
dann irgendwas besonders zeitkritisch werden, kann man es evtl. ja noch
rausnehmen.

von Xenu (Gast)


Lesenswert?

>Ach, Du arbeitest ohne Verzweigungsbefehle?

Hehe. Freilich benutze ich die auch.

Aber wenn ich zum Beispiel eine ADC-Interruptroutine habe,
die so wie unten ausschaut, würde es mich schon interessieren, wozu ich
dann das SREG speichern soll:

adc_finish: in adc_data, ADCH
            out UDR, adc_data
            reti

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.