Adok's Way to Assembler
Folge 5

Willkommen  zur  fnften  Folge des  Assembler-Kurses!  Diesmal  geht's um das
Ansprechen  des Flag-Registers, einige weitere Stack-Befehle, Bitverknpfungen
und  Shift-Befehle  (wie  ihr  sehen  werdet,  in  einem flieenden bergang).
Auerdem gibt's ein bichen was (nmlich alles :) ) zum Thema Ports.

+++ PUSHF und POPF +++

Wie  kann man das Flag-Register verndern? Zum  einen gibt es Befehle wie STI,
CLI, STD, CLD etc. Damit lassen sich jedoch nur bestimmte Flags verndern. Was
ist,  wenn  man andere Flags oder mehrere  auf einmal verndern will? Das lt
sich  leicht  mit Hilfe des Stacks  realisieren.  Der Befehl PUSHF sichert das
Flag-Register  auf  den Stack, der Befehl POPF  holt  einen Wert vom Stack und
setzt das Flag-Register auf diesen Wert. "Aha!" wird bei manchen von euch wohl
schon ein Licht aufgehen! Wenn man das Flag-Register auf einen bestimmten Wert
setzen will, so kann man diesen Wert auf den Stack sichern und mit POPF in das
Flag-Register schreiben. Das wrde im Programm so aussehen:

PUSH wert
POPF

Wie ihr seht, ist es also kein groes Problem, das Flag-Register zu verndern!
Allerdings  wird bei dieser Methode  das Flag-Register berschrieben. Was ist,
wenn  man  nur  einzelne Bits verndern,  die  anderen gleich lassen will? Das
wrde grob so aussehen:

;Hole Flags in AX:
PUSHF
POP AX
;nun schreibt man die Befehle, um die Flags (=Bits) zu verndern
;danach wird das Flag-Register gesetzt:
PUSH AX
POPF

Welche   Befehle  bentigt  man,  um  die  Bits  zu  verndern?  Richtig,  die
Bitverknpfungen.  Fr  diejenigen, die zuvor  noch  in keiner anderen Sprache
programmiert  haben oder die Bitverknpfungen  nicht kennen, folgt ein kleiner
Exkurs.

+++ Funktionsweise der Bitverknpfungen +++

- Die einfachste Verknpfung ist die NOT-Verknpfung.  Sie invertiert die Bits
  eines Bytes oder eines Words.  Beispiel: Nehmen wir an, AH enthalte den Wert
  11001010b.  Nach der Anweisung  NOT AH  betrgt  AH 00110101b. (Das kleine b
  kennzeichnet in Assembler Binrzahlen.)

- Die AND-Verknpfung (bitweises UND) erwartet  bereits  zwei  Parameter.  Das
  Ziel  wird  mit  der Quelle AND-verknpft. Das Ergebnis der Verknpfung wird
  wiederum in das Ziel geschrieben.  Wie funktioniert die AND-Verknpfung? Ich
  zeige es euch an einer Wertetabelle:

         1100b
  AND    1010b
  ergibt 1000b

  Das heit, es mu sowohl in der Quelle als auch im Ziel  an  der  jeweiligen
  Position ein Bit gesetzt sein,  damit auch im Ergebnis ein Bit gesetzt wird.
  Ansonsten wird das Bit im Ergebnis gelscht.  Anschlieend wird das Ergebnis
  in das Zielregister bzw. in die Zielspeicherstelle geschrieben.

- Die  OR-Verknpfung  (bitweises  ODER)  erwartet ihre Parameter wie AND, hat
  jedoch eine andere Wertetabelle:

         1100b
  OR     1010b
  ergibt 1110b

  Das  heit,  es  mu sowohl in der Quelle als auch im Ziel an der jeweiligen
  Position ein Bit gelscht sein, damit auch  im  Ergebnis  ein  Bit  gelscht
  wird. Ansonsten wird das Bit im Ergebnis gesetzt.

- Last but not least  lautet die Wertetabelle  der XOR-Verknpfung  (bitweises
  ENTWEDER-ODER):

         1100b
  XOR    1010b
  ergibt 0110b

  Es wird also nur dann ein Bit an einer bestimmten Position gesetzt,  wenn es
  ENTWEDER im Ziel ODER in der Quelle gesetzt ist. Wenn jedoch Quelle und Ziel
  an derselben Stelle das gleiche Bit haben, wird es im Ergebnis gelscht!

  (Nun wissen wir auch schon, warum XOR reg,reg das Reg lscht.  Verknpfe ich
  einen Wert mit sich selbst,  so haben Quelle und Ziel auf jeder Position das
  gleiche Bit.)

So, wie lt sich dieses Wissen anwenden? Wie lassen sich einzelne Bits setzen
oder lschen? Ganz einfach!

- Bits lassen sich mit der OR-Verknpfung setzen.  Wollen  wir  beispielsweise
  Bit 3  im  AL-Register setzen und  die anderen Bits  unverndert lassen,  so
  schreiben wir:

  OR AL,00001000b

  (Damit  keine Miverstndnisse entstehen: Bits werden von rechts nach  links
  gezhlt. Von rechts nach links kommt zuerst Bit 0, dann Bit 1 etc.)

  Warum  ist  das  so?  Nun, die Nullen bewirken bei OR, da  die  Bits  nicht
  verndert  werden.  Und auf die Position, bei der wir das  Bit  auf 1 setzen
  wollen,  schreiben wir 1.  Damit wird das Bit auf jeden Fall gesetzt,  egal,
  welchen  Wert  es  vorher  enthielt.  (... Verwirrung? Tja, den meisten ASM-
  Neulingen  ist  es  bei  diesem Thema nicht anders gegangen, falls sie nicht
  schon vorher die boolesche  Algebra  beherrschten.  Seht  euch  einfach  die
  Wertetabellen noch einmal an und denkt nach.)

- Mit AND lassen sich Bits wieder lschen. Hier geht's genau umgekehrt wie bei
  OR. Das heit, wenn wir Bit 3 von AL lschen wollen, schreiben wir:

  AND AL,11110111b

  Nach genauerem  berlegen ist  es doch logisch, oder?  Bei AND  bewirken die
  Einsen, da die Bits nicht gelscht werden,  und die Nullen lschen die Bits
  auf einen Schlag.

Hier nun ein Beispiel, wie man das Zeroflag (Bit 6) lschen kann:

PUSHF
POP AX
AND AX,1111111110111111b
PUSH AX
POPF

Und gesetzt wird es mit:

PUSHF
POP AX
OR AX,1000000b
PUSH AX
POPF

OK,  so  weit, so gut... Wie gesagt,  falls etwas nicht klar ist, Wertetabelle
ansehen oder, wenn's wirklich nicht anders geht, mich fragen.

+++ Shift-Befehle +++

Shift-Befehle,  auch Bitschiebeoperatoren genannt, sind eine schnelle Form der
Multiplikation. Mit

SHL Reg,Anzahl

wird  ein  Register um die angegebene  Anzahl  von Bits nach links verschoben,
also  praktisch  mit 2 hoch Anzahl multipliziert.  Ebenso gibt es SHR, um Bits
nach  rechts  zu  verschieben, also zu  dividieren!  Diese beiden Befehle sind
wesentlich  schneller  als  die  universellen  Arithmetikoperationen,  die wir
spter kennenlernen werden.

Und  SHL  kann uns auerdem bei noch  etwas  helfen! Nehmen wir an, wir wollen
eine Routine schreiben, die ein bestimmtes Bit eines Registers - sagen wir, AX
-  setzt.  Im Gegensatz zu obengenannten  Routinen  wissen wir jedoch nicht im
voraus,  welches Bit gesetzt werden soll, sondern nur, da die Nummer des Bits
in  der Byte-Variablen bitnr zu finden sei.  Wie erstellt man daraus die Maske
fr den OR-Befehl? Ganz einfach: Mit Hilfe von SHL. Und zwar so:

MOV BX,1             ;Gesetztes Bit in BX
MOV CL,BYTE PTR bitnr;Nummer der Position holen
SHL BX,CL            ;Gesetztes Bit auf richtige Position schieben

Nehmen  wir als Beispiel an, wir wollen Bit  3 setzen. Also mu bitnr gleich 3
sein.  Nun  wird  Bit 0 in BX  gesetzt  und in CL geschrieben, welche Position
gesetzt werden soll - also, um welche Anzahl von Bits BX nach links verschoben
werden  soll. Als nchstes SHL - tralalalala, wir haben die Maske erstellt. BX
ist  nun  gleich  00001000b, und mit  OR  AX,BX  fhren wir die Bitverknpfung
durch.

Beim  Lschen  eines Bits wird es  ein  wenig komplizierter. Zuerst fhren wir
obige  drei Befehle durch, die schon beim  Setzen eines Bits ntig sind. Damit
AND  korrekt  arbeitet,  mssen wir jedoch  noch  die Bits invertieren. Nichts
leichter als das! Wir schreiben:

NOT BX

Dann  ist BX gleich 11110111b, und die Sache hat sich erledigt! AND AX,BX, und
wir sind fertig.

Zum Schlu noch einige Worte zu den Themen Stack, Shift und AND:

- Wer  den  Stack  in  EXE-Dateien verwenden will, benutzt am besten am Anfang
  seines Programms die vereinfachte Segmentanweisung

  .STACK Groesse

  Wenn   ihr  also  z.B.  .STACK 255  schreibt,  wird  ein  255  Byte   groes
  Stacksegment definiert, das ihr alsgleich mit PUSH und POP ansprechen knnt.
  Um  das ASSUME-Zeug  braucht ihr euch  nicht  zu  kmmern,  das erledigt der
  Assembler automatisch.

  Ebenso   existieren   fr   Code-   und   Datensegment   die   vereinfachten
  Segmentanweisungen  .CODE und .DATA.  Die Gre mu hierbei nicht  angegeben
  werden,  Punkt vor .CODE und .DATA aber  nicht vergessen! Wenn ihr  auerdem
  am  Anfang eures Programms die ASM-Direktive  (Direktiven sind Befehle,  die
  den  Assembler bzw. den Compiler beeinflussen) DOSSEG schreibt,  werden  die
  Segmente automatisch in einer bestimmten Reihenfolge angeordnet, die von den
  meisten DOS-Programmen verwendet wird.

- Der  Parameter  Anzahl  bei den Shift-Befehlen funktioniert  erst  ab  einem
  80286-Prozessor.  Wollt  ihr, da eure Programme auch auf  lteren  Systemen
  laufen, so mt ihr statt SHL AX,6 sechsmal hintereinander SHL AX schreiben.
  Und unsere Bitsetz- und -lschroutinen mssen umgeschrieben werden:

    MOV BX,1             ;Gesetztes Bit in BX
    XOR CH,CH            ;CH lschen
    MOV CL,BYTE PTR bitnr;Nummer der Position holen
    JCXZ shiftlbl2       ;Wenn CX=0 -> nicht shiften
  shiftlbl1:
    SHL BX               ;Um eine Position nach links shiften
    DEC CL               ;CL erniedrigen
    OR CL,CL             ;CL=0?
    JNE shiftlbl1        ;Wenn nein, zu Label 1
  shiftlbl2:

  Danach kann ganz normal geORt oder mit Hilfe von NOT geANDet werden.

- Der Befehl TEST fhrt auch eine AND-Verknpfung durch,  lt jedoch das Ziel
  unverndert.  TEST ist also fr AND das, was CMP fr SUB ist.  Wozu TEST gut
  ist?  Try it out!  Es lt sich mit Hilfe von TEST und Zeroflag abfragen, ob
  ein Bit gesetzt oder gelscht ist.

+++ OUT und IN +++

Mit  OUT  und IN lassen sich die Ports  ansprechen.  Mit OUT wird ein Port auf
einen Wert gesetzt, mit IN ein Port ausgelesen. Die Nummer des Ports mu in DX
angegeben  werden,  der  Wert,  der geOUTet oder  in  den  das Ergebnis von IN
geschrieben  werden  soll, in AL. Dann schreibt  man OUT DX,AL bzw. IN AL,DX -
und schon hat man getan, was man tun wollte.

Sonderformen  der  Portbefehle: Wird statt AL  AX  verwendet, so knnen gleich
zwei  Ports beschrieben werden, wobei der Port  mit der Nummer aus DX den Wert
von  AH  zugewiesen  bekommt  und der mit  der  Nummer  DX+1  den Wert von AL.
Bestimmte Ports knnen auerdem direkt angesprochen werden, also OUT Nummer,AL
etc. Es handelt sich um jene Ports, deren Nummern in ein Byte passen.

Mit  Hilfe  der  Portbefehle kann man  mit  der Hardware des PCs (Grafikkarte,
Schnittstellen   etc.)  in  Kontakt  treten.  Fast  jedes  Demo  mu  von  den
Portbefehlen Gebrauch nehmen.

So,  das war diese Folge des Kurses.  Viel Theorie, wenig Praktisches, und die
Theorie  findet teilweise auch gar  keine praktische Verwendung. Dennoch mute
es   sein.  Jetzt  haben  wir  wenigstens  die  absoluten  Grundtechniken  der
Assembler-Programmierung   durch   (das,  was  jeder   Coder   im  Kopf  haben
mu/sollte).  In  der nchsten Folge  werden  wichtige Befehle besprochen, und
danach  knnten  wir  uns  vielleicht  noch  mit  fortgeschrittenen  Techniken
beschftigen. Seid froh! Euer Adok.
