Wie kann ich den Bedingungscode in Assemblersprache festlegen?

7

Ich möchte das Variablenzeichen testen. Mit anderen Worten, ich möchte wissen, ob eine Variable positiv oder negativ ist. Wie kann ich folgende Wenn-Dann-Sonst-Bedingungen in Assemblersprache schreiben?

  if X > 0 
      goto A
  else 
      goto B

Ich benutze PİC16f87x

Um meine Frage allgemeiner zu gestalten: Wenn Sie wissen, können Sie die folgenden Fragen beantworten?

ich.)

    if X > Y 
        goto A
    else 
        goto B

ii.)

    if X >= Y 
        goto A
    else 
        goto B

iii.)

    if X != Y 
        goto A
    else 
        goto B
JRobert
quelle
2
Ich erinnere mich an den Assembler-Code z80, aber Sie erreichen den Vergleich mit der Subtraktion und überprüfen den Übertrag und das Nullbit
clabacchio

Antworten:

11

Ich bin mit dem PIC-Mikrocontroller nicht vertraut, daher werde ich eine allgemeinere Antwort geben. (Bearbeiten: PIC-spezifische Antwort am Ende dieses Beitrags hinzugefügt)

Insbesondere kleinere Mikrocontroller wie 8-Bit und ihre Ableitungen sind in ihrer Leistung in einem einzigen Befehl begrenzt. Ein Befehl kann die Zieladresse für einen Sprung enthalten, aber nicht zwei davon, then-elseist also out. Sie haben nur das if-thenTeil, aber das ist genug. Es gibt zwei Ansätze. Bei einigen Controllern können Sie zu einer bestimmten Adresse springen, wenn eine Bedingung erfüllt ist, bei anderen können Sie nur die nächste Anweisung überspringen. Im ersteren Fall sieht Ihr Code wie folgt aus:

              if-test-succeeds goto test-success
test-failed   first instruction of `else` block
              ...
              goto continue
test-success  first instruction of `then` block
              ...
continue      first instruction after if-then-else

Wenn Sie nur die nächste Anweisung überspringen können, schreiben Sie so etwas wie

              if-test-succeeds skip next instruction
              goto test-failed
test-success  first instruction of `then` block
              ...
              goto continue
test-failed   first instruction of `else` block
              ...
continue      first instruction after if-then-else  

Der Test selbst hat auch begrenzte Möglichkeiten. Als ob Sie nicht zwei Zahlen übergeben können, um sie zu vergleichen. Sie laden den Akku mit der ersten Zahl und subtrahieren in der nächsten Anweisung die zweite Zahl. Dies führt dazu, dass Bedingungscodes wie die Null- und Übertragsflags gesetzt / gelöscht werden. Bedingte Anweisungen testen diese Flags. Also, wenn Sie schreiben möchten, if A = B then do-equal else do-not-equalwürde dies werden

              load accumulator with A
              subtract B from accumulator
              if zero-flag set goto do-equal
do-not-equal  first instruction of `else` block
              ...
              goto continue
do-equal      first instruction of `then` block
              ...
continue      first instruction after if-then-else

Wichtig: In der Bedienungsanleitung wird angegeben, welche Bedingungscodes von einer bestimmten Anweisung betroffen sind. Zum Beispiel kann der in dem Z80 - ldBefehl (für „Last Akkumulator“) wird nicht alle Flags ändern. Hier wird also der Akku geladen nicht aus, um festzustellen, ob die Daten Null sind.



OK bearbeiten , also habe ich einige Nachforschungen angestellt und Folgendes gefunden:
Der PIC hat nur 2 bedingte Sprunganweisungen, BTFSSund BTFSC.

BTFSS : Bittest F, Überspringen, wenn gesetzt
Syntax: BTFSS f, b
wobei f ein Register [0..127]
und b das Bit in dem zu testenden
Register ist [0..7] Beschreibung: Wenn das Bit im Register ist 0Der nächste Befehl wird ausgeführt. Wenn das Bit ist1 der nächste Befehl verworfen und NOPstattdessen a ausgeführt.

BTFSC : Bittest F, Überspringen, wenn
gelöscht Syntax: BTFSC f, b
wobei f ein Register [0..127]
und b das Bit in dem zu testenden
Register ist [0..7] Beschreibung: Wenn das Bit im Register ist 1Der nächste Befehl wird ausgeführt. Wenn das Bit ist, wird 0der nächste Befehl verworfen und NOPstattdessen a ausgeführt.

stevenvh
quelle
6

Um zu testen, ob eine Ganzzahl negativ ist, müssen Sie nur das oberste Bit testen. Wenn das oberste Bit 1 ist, ist es negativ.

Für eine 8-Bit-Ganzzahl auf einem erwähnten 8-Bit-Clabacchio können Sie nun eine Subtraktion verwenden, um den Test durchzuführen. Dies ist jedoch in der Regel nicht optimal:

  1. PICs haben die nützlichen Anweisungen btfsc und btfss, mit denen Sie das oberste Bit direkt testen können, wie rokjarc erwähnt hat. Dies kann sogar verwendet werden, um 16- und 32-Bit-Ganzzahlen (und sogar Floats!) Zu testen.

Dies ist auch in C erwähnenswert, da ich gesehen habe, dass die Microchip C-Compiler dummen Code produzieren. Wenn getestet wird, ob eine 16-Bit-Ganzzahl größer als Null ist, wird buchstäblich die Assembly erzeugt, um die Ganzzahl von Null zu subtrahieren und die Flags zu überprüfen, anstatt einfach das btfss zu verwenden.

Wenn ich also PIC C schreibe, überprüfe ich immer die Assembly-Ausgabe, um festzustellen, ob sie sinnvoll aussieht. Und dann schreiben Sie normalerweise Makros, um die Operationen auszuführen. (Übrigens, ich habe diese Makros nicht wirklich überprüft, sie sind mir nur ein Rätsel).

#define IF_NEGATIVE_16_BIT(x) if (*((int8*)((&x)+1)) & 0x80)
#define IF_NEGATIVE_32_BIT(x) if (*((int8*)((&x)+3)) & 0x80)
  1. Andere Mikrocontroller haben den AND-Befehl. Nur UND das oberste Byte der Ganzzahl mit 0x80. Wenn das Null-Flag gesetzt wird, war die Ganzzahl nicht negativ.
Raketenmagnet
quelle
6

Um ganzzahlige Vergleiche und fast alles andere in Assemblersprache durchführen zu können, müssen Sie verstehen, wie die Zahlen dargestellt werden.

Die meisten Variablen in einem kleinen eingebetteten System sind nicht signiert oder sollten es zumindest sein. Hochrangige Sprachprogrammierer, die an größere Systeme gewöhnt sind, neigen dazu, nicht darüber nachzudenken und signierte Variablen zu verwenden, wenn nur nicht signierte benötigt werden. Unsignierte sind im Allgemeinen auf niedriger Ebene einfacher zu bearbeiten.

Ihr Code ist für einen PIC 16, daher gehe ich davon aus, dass Sie den MPASM-Assembler verwenden. Ich habe eine Reihe von Makros und anderen Funktionen, die beim Vergleichen der Größe in meiner allgemeinen Include-Datei STD.INS.ASPIC helfen , die Teil meiner PIC-Entwicklungsumgebung ist . Insbesondere dienen die Makros SKIP_WLE (überspringen, wenn W kleiner oder gleich war) und SKIP_WGT (überspringen, wenn W größer als war) zum Vergleichen von Zahlen ohne Vorzeichen.

Der PIC hat ein Übertragsstatusbit namens C, das der Übertragsausgang der ALU ist. Dieses Bit kann nach einem Addieren oder Subtrahieren getestet werden, um festzustellen, ob das High-Bit der ALU übertragen wurde. Die Art und Weise, wie Subtrahieren mit Zweierkomplementzahlen funktioniert, wird das C-Bit nach einem Subtrahieren zu einem nicht geliehenen Bit. Um die Sache komplizierter zu machen, subtrahieren die PIC-Subtraktionsbefehle das W-Register vom Operanden und nicht umgekehrt. Sie müssen einige mentale Gymnastik machen, um zu verfolgen, dass C nicht ausgeliehen ist und was wirklich von dem abgezogen wurde, was und daher was ein Ausleihen tatsächlich bedeutet. Ich habe das alles einmal gemacht und das Ergebnis in diesen beiden einfachen Makros zusammengefasst, damit ich nicht jedes Mal darüber nachdenken und die Chance nutzen muss, es durcheinander zu bringen. Auf einem PIC 16 wird SKIP_WLE zum Einzelbefehl BTFSS STATUS, C, und SKIP_WGT wird zum BTFSC STATUS, C.

So würden Sie diese Makros im Code verwenden:

maxok equ 37; maximaler OK Tankfüllstand
         ...
;;
;; Überprüfen Sie den Tankfüllstand und führen Sie die Ausnahmeroutine aus, falls dies der Fall ist
;; zu hoch.
;;
         banksel tanklev; Bank für den Zugang zu TANKLEV einstellen
         movf tanklev, w; den Tank voll auffüllen
         sublw maxok, vergleiche mit maximalem Normalpegel
         skip_wle; Tankfüllstand liegt in Reichweite?
         gehe zu ohcrap, nein
;;
;; Der Tankfüllstand liegt innerhalb der normalen Betriebsgrenzen.
;;

Es gibt viele andere nützliche Dinge in STD.INS.ASPIC. Ich habe auch einen Präprozessor , der der MPASM-Sprache viele nützliche Funktionen hinzufügt. Zum Beispiel kann es zur Erstellungszeit Gleitkomma-Berechnungen durchführen, echte Zeichenfolgenmanipulationen zum Erstellen von Symbolnamen durchführen, verfügt über eine flexiblere Makrofunktion und vieles mehr.

Olin Lathrop
quelle
6

Ich werde vorerst nur den ersten Teil der Frage beantworten.

Sie erwähnen den Typ von X nicht - nehmen wir an, es ist ein signiertes Zeichen. Das vorzeichenbehaftete Zeichen hat b.7 == 1, wenn es negativ ist, daher müssen wir nur den Status dieses Bits überprüfen.

//checking if bit 7 of X is cleared (X.7 == 0)
BTFSC   X,7    //if X.7 == 0 (X is positive) we'll skip the next instruction
GOTO    B
GOTO    A

//checking if bit 7 of X is set (X.7 == 1)
BTFSS   X,7    //if X.7 == 1 (X is negative) we'll skip the next instruction
GOTO    A
GOTO    B

Hier ist ein Link zu einer netten Anleitung: Eine Anleitung zu gängigen PIC-Assembly-Programmierkonstrukten

Das obige Beispiel finden Sie auf Seite 7.

Versuchen Sie, den Rest der Antworten selbst herauszufinden. Hinweis: Clabacchios Kommentar ist sehr nützlich.

Rok Jarc
quelle
Ist das dasselbe wie: Jason Thweatt. "Eine Anleitung zu gängigen PIC-Assembly-Programmierkonstrukten". ucpic.byethost7.com/Downloads/ApuntesAssembler/Apunte2.pdf ?
Davidcary
Ja! danke für die Heads-Ups, ich habe nicht bemerkt, dass der alte Link nicht funktioniert. wird bearbeiten.
Rok Jarc
0

16 Bit Vergleiche

  • X = XH: XL die Hi und Lo Bytes der RAM Variablen X,
  • Y = YH: YL die Hi- und Lo-Bytes der RAM-Variablen Y.

Alle Werte sind ohne Vorzeichen.

; if( y < x )
  movfw XL
  subwf YL,w
  movfw XH
  skpc ; c=0 indicates a borrow we need to propagate.
    incfsz XH,w ; handle XH=0xff correctly, unlike ``incf XH,w''.
      subwf YH,w
  skpnc
    goto else
; then:
; /* y is less than x */
  ...
  goto endif
else:
; /* y is NOT less than x */
  ...
endif:

; if( x <= y )
  movfw XL
  subwf YL,w
  movfw XH
  skpc ; c=0 indicates a borrow we need to propagate.
    incfsz XH,w ; handle XH=0xff correctly, unlike ``incf XH,w''.
      subwf YH,w
  skpc
    goto else
; then:
; /* x is less than or equal to y */
  ...
  goto endif
else:
; /* x is NOT less than or equal to y */
  ...
endif:

; if(X == Y)
  movf XH,w
  xorwf YH,w
  skpz
  goto else
  movf XL,w
  xorwf YL
  skpz
  goto else
; then:
; /* X equals Y */
  ...
  goto endif
else:
; /* X is not the same as Y */
  ...
endif:

Assembler-Programmierer ändern normalerweise die Tags "else:" und "endif:" in eine eindeutige (und hoffentlich beschreibende) Bezeichnung für jede if-Anweisung. Vielleicht so etwas wie "then_in_normal_range:", "else_outside_normal_range:" und "finish_range_handling:". (Im Gegensatz zu höheren Sprachen wie Pascal und BASIC, in denen wir für jede if-Anweisung dieselben Wörter "then" und "else" und "endif" verwenden.)

Der obige Code funktioniert nur, wenn sich sowohl X als auch Y im RAM befinden. - Der PIC16f87x erfordert unterschiedliche Anweisungen, um X mit einem konstanten Wert zu vergleichen.

Eine Möglichkeit, mit 16-Bit-Vorzeichen umzugehen, besteht darin, zuerst das High-Bit umzudrehen

movlw 0x80
xorwf XH,w
xorwf YH,w

Verwenden Sie dann den obigen Vergleichscode. Stellen Sie später die ursprünglichen Werte wieder her, indem Sie das High-Bit erneut umdrehen

movlw 0x80
xorwf XH,w
xorwf YH,w

.

ps Sie können häufig eine viel schnellere Antwort auf Fragen zum PIC16f87x erhalten, indem Sie die PIClist-Website http://piclist.com/ und das Microchip-Wiki http://microchip.wikidot.com durchsuchen . Vergleiche zwischen Assemblersprachen finden Sie auf der Seite "Assemblersprachenvergleiche" im Microchip-Wiki und unter PIC Microcontroller Comparison Math Methods auf der PIClist-Website (von denen das Obige ein kleiner Auszug ist).

Davidcary
quelle