Warum wurde dieser Code nicht viel einfacher geschrieben?

Ich bin auf eine Frage gestoßen, während ich an Assemblersprache gearbeitet habe. Hier ist die Frage:

Angenommen, Bit P2.2 wird verwendet, um eine Außenbeleuchtung und Bit P2.5 eine Beleuchtung innerhalb eines Gebäudes zu steuern. Zeigen Sie, wie man das Außenlicht einschaltet und das Innenlicht ausschaltet.

Gegebene Lösung:

SETB C            ; CY = 1
ORL C, P2.2       ; CY = P2.2 ORed w/ CY
MOV P2.2, C       ; turn it on if not on
CLR C             ; CY = 0
ANL C, P2.5       ; CY = P2.5 ANDed w/P2.5
MOV P2.5,C        ; turn it off if not off

Ich hatte einfach das Gefühl, dass es genauso funktionieren würde, um zu codieren:

SETB P2.2
CLR P2.5

Was stimmt damit nicht?

Vielleicht nur Didaktik - zeigt, wie man das Carry-Bit als Akkumulator verwendet. Einen Vorteil sehe ich in diesem speziellen Fall nicht. Das sieht aus wie 8051-Assembler-Code.
@SpehroPefhany Aber soweit ich weiß, wird das Acc-Register in einigen Fällen verwendet, da es das einzige Register ist, das einige Befehle wie DA, RR, RL usw. unterstützt. Ich glaube nicht, dass dies hier der Fall ist. Liege ich falsch?
Der Carry ist ein bisschen breit. Möglicherweise möchten Sie es in einigen Fällen als Akkumulator verwenden, z. B. bei der Ladder-Logic-Auswertung.

Antworten (5)

Sie haben Recht, dass der von Ihnen angezeigte Code albern zu sein scheint. Vielleicht kann die Maschine, auf der dies ausgeführt wird, keine sofortigen Operationen ausführen, um Bits an E / A-Ports zu setzen, und deshalb ist so etwas wie SETB P2.2 nicht möglich.

Das CY-Bit immer noch auf 1 zu setzen und dann alles mit OR zu verknüpfen, ist einfach nur albern. Dasselbe gilt für das Setzen des CY-Bits auf 0 und das anschließende UND-Verknüpfen von etwas darin. Natürlich kann das CY-Bit direkt in ein I/O-Pin-Bit kopiert werden, da der Code dies tut. Das sollten höchstens 4 Anweisungen sein, auf keinen Fall 6.

Ich kann also sagen, dass ich, wenn ein Bit bitadressierbar ist, Bitbefehle für jedes Bit verwenden darf, richtig?
@İlk: Nicht unbedingt. Es kann Einschränkungen geben, dass die Bitbefehle nur mit bestimmten Registern, bestimmten "nahen" Speichern und dergleichen funktionieren. Ohne den Prozessor zu kennen, können wir nicht sicher sagen, ob SETB P2.2 möglich gewesen wäre. SETB C gefolgt von MOV P2.2, C, ist jedoch eindeutig möglich.
@OlinLathrop: Der Prozessor ist mit ziemlicher Sicherheit eine 8051-Variante, und der Befehlssatz für diese würde die Verwendung derselben Speicherorte SETB bitund CLR bitAnweisungen wie für MOV bit,C. Während die Verwendung diskreter Anweisungen zum Lesen eines E/A-Ports, zum Aktualisieren des Werts und zum Zurückschreiben zu einer anderen Semantik führt als die Verwendung von Lese-Modifizier-Schreib-Anweisungen, verwenden die bitweisen Anweisungen alle dieselbe Lese-Modifizier-Schreib-Semantik auf I /O-Ports.

Der Code ist mit ziemlicher Sicherheit für einen Prozessor bestimmt, der den 8051-Befehlssatz verwendet. Auf diesem Prozessor hätte die von Ihnen angegebene Codevariation die gleiche Wirkung wie das Original, außer dass sie schneller ausgeführt würde. Das Ausführen von "ORL C, P2.2", wenn Carry gesetzt ist, hat keine beobachtbaren Auswirkungen, außer dass eine gewisse Anzahl von Zyklen verschwendet wird (zwei CPU-Zyklen mit insgesamt 24 Taktzyklen auf einem 8051, wenn ich mich richtig erinnere; wahrscheinlich eine andere Anzahl bei einigen anderen Varianten) . Ebenso beim Ausführen von "ANL C,P2.5", wenn der Übertrag klar ist. Obwohl es einige Arten von Prozessoren geben kann, bei denen eine Anforderung zum Lesen einiger E / A-Positionen einen beobachtbaren Effekt hätte, glaube ich nicht, dass ein Prozessor im 8051-Stil jemals ein solches Verhalten für bitadressierbare E / A-Positionen gezeigt hat weniger für Bits von P2.

Vielleicht bestand der Zweck des Codes darin, die Anweisungen ORL C,bitund zu demonstrieren ANL C,bit, aber dies scheint ein seltsames Beispiel zu sein, um sie zu demonstrieren.

Der angegebene Assemblercode ist wahrscheinlich vom Compiler generiert. Es ist die nicht optimierte Version der folgenden C-Anweisungen, wobei P2_2und die bitadressierbaren P2_5Objekte sind:

P2_2 |= 1;
P2_5 &= 0;

Dies mag äquivalent zu P2_2 = 1;und P2_5 = 0;erscheinen, ist es aber nicht, wenn die bitadressierbaren Register flüchtige Objekte sind. Eine Read-Modify-Write-Operation für ein flüchtiges Objekt muss das Lesen und Schreiben in dieser Reihenfolge ausführen. Dadurch wird sichergestellt, dass etwaige Nebeneffekte beim Lesen oder Schreiben des Registers tatsächlich auftreten.

Obwohl ich kein 8051-Bit-adressierbares Register mit Nebeneffekten kenne, kann ein Compiler nicht davon ausgehen, dass es keines gibt oder jemals geben wird.

Guter Punkt darüber, dass es möglicherweise vom Compiler generiert wird. Allerdings stellt sich dann die Frage, warum jemand P2_2 |= 1 statt nur P2_2 = 1 schreiben würde.

Der wirkliche Unterschied zwischen diesen kann subtil sein.

In Ihrer vereinfachten Antwort liest die Logik den Port, setzt oder löscht den Bitwert und schreibt ihn dann wieder an den Port. Beachten Sie, dass der gesamte Port hier neu geschrieben werden könnte.

Die Lösung verwendet andererseits den MOV-Bit-Befehl, der auf ziemlich andere Weise arbeiten kann.

Ohne auf die Details des hier verwendeten speziellen Teils einzugehen, ist es schwierig festzustellen, ob es einen Unterschied gibt oder ob es darauf ankommt.

Oder es könnte einfach sein, dass der Ausbilder beschlossen hat, Sie zum Nachdenken anzuregen ... was schließlich ... seine eigentliche Aufgabe ist.

Die einzige Antwort ist, dass der Prozessor 1-Bit-Befehle nicht direkt unterstützt. Wenn jedoch das Übertragsbit verwendet wird, weiß es, dass nur ein Bit manipuliert wird.