Lucifer of ZeroBit - Ja ljublju ASSEMBLY VII. rész

        ÚÄÄÄ        ÚÄÄÄ     ÚÄ       ÚÄ
       ÚÄ  ÚÄ      ÚÄ   ÚÄ   ÚÄÚÄ   ÚÄÚÄ
      ÚÄ    ÚÄ      ÚÄÄ      ÚÄ  ÚÄÄ  ÚÄ
     ÚÄÄÄÄÄÄÄÄÄ       ÚÄÄ    ÚÄ   Ú   ÚÄ         Ja ljublju ASSEMBLY
     ÚÄÄ    ÚÄÄ   ÚÄ    ÚÄ   ÚÄ       ÚÄ             VII.rész
     ÚÄÄ    ÚÄÄ     ÚÄÄÄÄ    ÚÄ       ÚÄ

     Mielőtt még elkezdenénk, van egy kis tartozásom. A múltkor az OF bitről nem a teljes igazságot írtam, ezért újra leírom a funkcióját. Az OF (Overflow Flag) segít az ELÕJELES számok értelmezésében. Mikor egy mûveletet elvégez a proci, csak a sima bináris aritmetikát figyeli, nem foglalkozik előjel bitekkel és egyebekkel. De itt az OF bit, aminek éppen ez a feladata.

     Mikor mondjuk összeadjuk a 8343h és a 8654h számokat, akkor a proci összeadja őket, az eredmény helyére 0997h kerül és a CF bit 1 lesz, jelezve az átvitelt. De mi van, ha én a két számot előjelesen képzeltem el.
   Ebben segít a proci OF-fel foglalkozó része. A számok előjeles értékei: a 8343h-é -31933, a 8654h-é -31148. Ezeket összeadva az eredmény decimálisan -63081. Ez hexában 10997h. Látható, hogy az első négy számjegy itt is 0997h, mint a sima összeadásban, ezért az eredmény ezen részét nem kell bántani. Az SF bit nem tudja jelezni, hogy negatív számról van szó, mert a 0997h legmagasabb bitje 0. De akkor honnan tudjam, hogy az eredményt negatívan is lehet értelmezni? Ezt jelzi az OF, vagyis a 0997-et értelmezhetem negatívként is. Ekkor a szám elé kell még képzelni egy 1-est (gyakorlatilag az OF-et) és így kell számolni az előjeles értékét.

     Nézzünk egy példát arra, hogy mikor lesz 0 az OF.
   Adjuk össze a 0d958h és a 303fh számokat. Az eredmény 10997h. A sima összeadás eredménye itt is ugyanaz, mint az előző esetben. Az eredmény (pl.:AX) helyére 0997h kerül és a CF 1 lesz. Most értelmezzük a számokat előjellel. A 0d958h előjelesen értelmezve a -9896 decimális számot adja, míg a 303fh a 12351-et. Ezeket összeadva a decimális eredmény 2455. Azaz 0997h. Ezen látszik, hogy nem értelmezhető negatívként, szemben az 10997h-val. Ebben az esetben OF 0 lesz.

     Röviden az OF azt jelzi, ha egy előjelesen is értelmezhető szám nem fér el egy byteon (az előjelével együtt). Egy szón a legkisebb ábrázolható előjeles szám a -32768, a legnagyobb pedig a +32767. Egy byteon a legkisebb -128 a legnagyobb +127. Ha az eredmény előjeles értelmezése ennél kisebb vagy nagyobb lenne, az OF 1 lesz.

     Ahhoz, hogy a helyes számot megkapjuk (például képernyőre való kiíráshoz) a következőket kell tenni:
     1. Ha OF=0, akkor a számot kettes komplemensként felfogva írjuk ki. Tudjátok, mikor a 7. bit az előjel. Kiszámítását az előző számban olvashatjátok.

     2. Ha OF=1,
           - ha SF is 1, az eredmény úgy jó, ahogy van, pontosabban a szám
             elé még egy 0-t elképzelve kell számítani a KETTES KOMPLEMENSÁT.
           - ha SF=0, akkor az eredmény elé egy egyest helyezve számold ki
             a kettes komplemensét

     Példa:  az eredmény 0567h és SF=0, OF=1, akkor a helyes eredmény 10567h kettes komplemens értéke az eredmény 9234h és SF=OF=1, akkor az igazi eredmény 09234h kettes komplemensben

   Mindkét esetben használható értelemszerûen byte helyett szó.
   Persze ezzel csak akkor kell foglalkozni, ha előjeles számokkal dolgozol.

     (A kettes komplemens amúgy nem csak a számok értelmezését jelenti (úgy, ahogy az előző számban leírtam, hanem azt is, hogy két szám egymásnak kettes komplemense (kiegészítője), ha összegük nulla. Ehhez viszont kell a már leírt értelmezés.)

      Akkor mit is számít, hogy az előjeles vagy az előjel nélküli ugróutasítást használjuk. Nem kezdek elméleti fejtegetésekbe, mert azt lehet, hogy nem mindenki értené. Inkább 4 gyakorlati példán mutatom be a különbséget. Minden példa egy-egy számpárra fog épülni, amelyeket összehasonlítunk és megnézzük, hogy melyik ugrás mikor következik be.

     I. Először nézzük a 15h és a 34h számokat. Ezek bináris alakja: 15h=00010101b, 34h=00110100b. Amint látjátok mind a kettőt 8 bitre kiegészítve alakítottam át, mivel egy byte 8 bites. Most meg kell nézni, hogy a jelzőbitek hogy állítódnak be.
     A
CMP 15h,34h mûvelet lesz a kiindulópont. Ilyen mûvelet persze nincs, helyette a mov al,15h, CMP al,34h mûveletpárt kell alkalmazni, de most a rövidség kedvéért marad a sima CMP. Ez a 15h-34h mûveletet hajtja végre. Mivel a kivonandó kisebb, mint a kisebbítendő, ezért egy kölcsönzésre lesz szükség. Mindjárt kiderül, mi ez, bár ezzel tizes számrendszerû kivonásnál is találkoztatok.
   00010101b
         -00110100b           15h-34h=1e1h
       -----------
        111100001b

     Látható, hogy mikor a 0-1 mûveletet végezzük el (az 5. bitek kivonása), akkor a szomszédos helyiértékről kölcsönözni kell egy 1-est, hogy a 10b-1b mûveletet kapjuk, amit már el tudunk végezni. Ennek az eredménye 1b, amit le is írunk. Mehetünk tovább, de nem szabad elfelejteni a kölcsönt. A következő kivonás a 0b-0b lenne, de volt egy kölcsönzés, amit most visszaadunk, így lesz 0b-0b helyett 0b-1b. Ezt viszont megint csak kölcsönzéssel tudjuk elvégezni, de a kölcsönt megint visszaadjuk majd. Ez így megy addig, amíg van kivonandó helyiértékünk. Ha ezután is maradt még tartozásunk, akkor az leírjuk a mínusz jel alá, ahogy én is tettem. De egy byteban csak 0-7 bitek szerepelnek, a mínusz jel alatti számjegy pedig már a 8-ik bit (figyeljetek: a jobb szélső bit a 0-ik).

      Ezért ezt a plusz bitet a CF-be tesszük, ez jelzi, hogy a kivonás végén kölcsönzés volt, azaz a 15h kisebb, mint a 34h. A byte 7. bitje 1, ezért az SF jelzőbit 1 lesz. Mi lesz az OF-fel? A két számot előjelesnek feltételezve az eredmény -31 (0eah). Ez ábrázolható 1 byteon ezért OF=0 lesz.

     Végül mely ugróutasítások ugranak ez után (csak azokat nézem, amelyeknek van előjeles/nélküli párja).                                                 
     - JA és JAE nem ugrik mert CF=1. Vagyis a számokat előjel nélkül nézve 15h nem nagyobb, mint 34h.

     - JB és JBE elugrik, mert CF=1. A számokat előjel nélkül nézve 15h kisebb 34h-nál.

     - JG és JGE nem ugrik, mert SF<>OF. Előjelesen 15h nem nagyobb, mint 34h.

     - JL és JLE elugrik, mert SF<>OF. Előjelesen 15h kisebb 34h-nál.

     II. A következő számpár a 15h és a 87h legyen. Most már nem részletezem a kivonások menetét. Itt is a CMP 15h,87h az alap.
     A jelzőbitek állapota: 15h-87h=18eh. Az eredménybe 8eh kerül. CF=1 lesz, mert maradt egy kölcsönzés. SF is 1 lesz, mert 8eh 7. bitje 1. OF pedig 1 lesz, mert a számok előjeles értelmezése esetén az eredmény +142 (15h 21,87h -121 előjelesen, ezek különbsége 142). Ez a +142 előjelesen nem ábrázolható egy byteon, ezért lesz OF=1.

     Mik ugranak:
     - JA és JAE nem ugrik, mert CF=1. Előjel nélkül 15h nem nagyobb 87h-nál.
                                                                                
     - JB és JBE ugrik, mivel CF=1. 15h kisebb, mint 87h, előjel nélkl.

     - JG és JGE elugrik, mert SF=OF. Most figyelj: 15h előjelesen NAGYOBB 87h-nál (előjel nélkül kisebb, nézd meg JB-nél)

     - JL és JLE nem ugrik mert SF=OF. 15h előjelesen nem kisebb, mint 87h. Figyeld meg, hogy előjel nélkül kisebb.

   III. Most nézzük a 87h és 0b4h számokat.
     A jelzőbitek: 87h-0b4h=1d3h. Az eredményben 0d3h lesz. CF 1 lesz, mert volt kölcsön az utolsó helyiértéknél. SF is 1 mert 0d3h 7. bitje 1. OF viszont 0 lesz, mert előjelesen nézve a számokat (87h -121 és 0b4h -76) a -121-(-76)=-45 számot kapjuk, ami elfér egy byteon. A 0d3h-t előjelesen nézve éppen -45-öt kapunk.
     Az utasítások:
     - JA és JAE nem ugrik, mert CF=1. 87h nem nagyobb, mint 0b4h előjel nélkül.

     - JB és JBE ugrik, mert CF=1. Azaz előjel nélkül 87h kisebb 0b4h-nál

     - JG és JGE nem ugrik, mert SF<>OF. A 87h (-121) előjelesen nem nagyobb 0b4h-nál (-76).

     - JL és JLE ugrik, mivel SF<>OF. 87h előjelesen kisebb 0b4h-nál

   IV. Legyenek 0b4h és 87h a számok (az előző fordítottja)
     0b4h-87h=2dh. Ez alapján a jelzőbitek: CF=0, mert nem maradt kölcsönzés az utolsó helyiértékre. SF=0, mert 2dh 7. bitje 0. OF is 0, mert előjelesen számolva -76-(-121)=45, ami elfér egy byteon. Tehát 0b4h előjelesen nagyobb 87h-nál (SF=OF, ezért JG ugrik) és előjel nélkül is nagyobb (CF=0, azaz JA fog ugrani).

     Van még két lehetőség a számok viszonyára, mikor az I. vagy a II. pontot fordítjuk meg úgy , ahogy a IV. pont a III. fordítottja. Ezeket vezesd le magad. Az elgondolásod helyességét például Turbo Debuggerrel ellenőrizheted le.


     Nekiláthatunk a matematikai mûveleteknek.

 

ADD utasítás (ADDition):


     Használat:  ADD cél, forrás

     Összeadja a cél és forrás értékeket és a eredményt a cél-ba teszi. A cél és a forrás lehet byte vagy szó, de meg kell egyeznie a típusuknak. A lehetséges cél és forrásokat az ASM.NG-ből lehet megnézni (tőlem megszerezhető).
     Jelzőbitek:
       CF - 1 lesz, ha az utolsó helyiértéken volt átvitel, vagyis ha az eredmény nem fér be a célba. pl.: 98h+0d4h=16ch, ez nem fér el 1 byteon

       OF - 1 lesz, ha az eredmény előjelesen értelmezve nem fér be a célba pl.: 87h+87h=10eh, a célba 0eh kerül, de a valódi érték nem 14, -242 (10eh kettes komplemense), ha előjelesen dolgozunk

       ZF - 1, ha az eredmény nulla

       SF - 1, ha az eredmény 7. bitje 1

       AF - 1, ha a m–velet közben a legalsó négy bitről átvitel volt az 5. bitre

       PF - 1, ha az eredményben páros számú 1-es van
                                                                                
       Példa:

      MOV AX,1234h                ; AX-be az egyik összeadandó
         ADD AX,4536h                 ; AX=AX+4536h

 

ADC utasítás (ADd with Carry):


    Használat:  ADC cél, forrás

     Csak annyiban különbözik az ADD-tól, hogy cél=cél + forrás + CF.  Minden más egyezik. Ezt például duplaszavas összeadásnál használjuk, mikor az első összeadás esetleges átvitelét fel kell használni a másodiknál. Nem csak duplaszavas, hanem akárhány szavas összeadásra is alkalmas, csak tovább kell vinni.

     Példa:
    MOV AX,1234h          ; Ez most a 34561234h számhoz (BX:AX) adja
       ADD AX,0F564h         ; hozzá a 5436f564h számot. Két lépés kell:
       MOV BX,3456h         ; először összeadni az 1234h és a 0f564h
       ADC BX,5436h         ; számokat, majd az átvitel figyelembevé-
                                  ; telével összeadni a 3456h és az 5436h
                                 ; számokat     
                                

 

SUB utasítás (SUBtraction):


     Használat:  SUB cél, forrás

     A cél=cél - forrás m–veletet hajtja végre. A cél és a forrás lehet byte vagy szó. A forrás lehet byte hosszúságú is, ha a cél egy szó. Ekkor a byteot 16 bitesre kiterjeszti kivonás előtt.

     A jelzőbitek ugyanakkor állítódnak be, mint összeadáskor.

 

SBB utasítás (SuBtract with Borrow):


     Használat:  SBB cél, forrás

     A különbség a SUB-hoz képest annyi, hogy ez a cél=cél - forrás - CF mûveletet végzi el. Több szóból álló kivonásnál hasznos, mert az előző kivonások esetleges kölcsönzéseit (borrow) figyelembe veszi.

     Példa:                                                                     
    MOV AX,1234h                 ; A 64561234h-76873456h m–veletet kell
       SUB AX,3456h                 ; elvégezni. Először 1234h-ból ki kell
       MOV BX,6456h                 ; vonni 3456h-t, majd az esetleges
       SBB BX,7687h                 ; átvitelt figyelembe véve 6456h-ból le
                                    ; kell vonni 7687h-t


     A szorzás, osztás és a többiek a következő cikkben.

Lucifer of ZeroBit

Š2000. Fearless Criminal Force. Minden jog fenntartva!