Tm tiedosto on koottu CyberDyne Magazine:ssa ilmestyneen
'Assy Ohjelmointikurssi' -sarjan neljnnest osasta. Sen
levittminen elektronisessa muodossa muuttamattomana on
sallittua ja jokainen saa omaa kyttn varten printata
sen kokonaisuudessaan tai osia siit. Sarjan toimitti
alunperin Antti Niskanen. Tmn tiedoston on koonnut
Antti Niskanen.

=====Kurssin neljs osa===============================================
=====Ilmestyi numerossa 12/94==============================================


    Tss osassa kurssia vilkaisemme hieman, miten symbolisella konekielel-
    l voidaan suorittaa matematiikkaa. 
    
    Kaikkein yksinkertaisin laskutoimitus on koulun ensimmisell  luokalla 
    opittu yhteenlasku. Tietokone voi ynnt kaksi lukua komennolla: 

    ADD <kohde>,<lhde>

    Komento laskee yhteen lhteen ja kohteen ja kirjoittaa tuloksen kohtee-
    seen. Kohde voi olla rekisteri tai muistiosoite,  lhde voi olla rekis-
    teri tai muistiosoite tai suora lukuarvo. Kohteessa ja lhteess tytyy 
    olla yht monta bitti,  jotta komento olisi laillinen.  Emme siis  voi 
    kytt  ADD AX,BL kaltaisia komentoja,  sill AX on 16-bittinen ja  BL 
    vain 8-bittinen. Voimme sen sijaan list AX:n rekisterin BX sislln 
    komennolla ADD AX,BX. Vastaavasti voimme list muistiosoitteessa 1234h 
    olevaan   16-bittiseen   lukuun    AX:ss   olevan   luvun   komennolla 
    ADD  [1234],AX tai voimme list AX:n osoitteessa 1234h olevan  luvun 
    komennolla  ADD AX,[1234].  AX:ss olevaa lukua voi kasvattaa 1AC4h:lla 
    komennolla  ADD  AX,1AC4   ja AH:ssa olevaa lukua voi  kasvattaa  4:ll 
    komennolla  ADD  AH,04.  ADD-komennossakin on rajoituksia  -  muistissa 
    olevaan  lukuun ei voi list toista muistissa olevaa lukua.   Tm  on 
    tehtv siirtmll ensin listtv luku rekisteriin,  esim.  AX:n ja 
    lismll sitten kohteeseen AX. 

    Tss on taulukko sallituista ADD-komennon muodoista:

    ADD r8,r8           ADD r8,l8               ADD r8,m8
    ADD r16,r16         ADD r16,l16             ADD r16,m16
    ADD m8,r8           ADD m8,l8
    ADD m16,r16         ADD m16,l16

    l8 ja l16 tarkoittavat 8- ja 16-bittisi lukuja, r8 ja r16 tarkoittavat 
    8-  ja 16-bittisi rekistereit ja m8  ja m16  tarkoittavat 8-  ja  16-
    bittisi  muistissa olevia lukuja.  Muistissa olevia lukuja  osoitetaan 
    samalla  tavalla  riippumatta siit,  onko luku  8-   vai  16-bittinen. 
    Prosessori itse ptt onko kyseess 8-  vai 16-bittinen luku riippuen 
    siit,   onko kohteena tai lhteen 8-  vai 16-bittinen rekisteri.  Kun 
    listn muistiin suoraa lukuarvoa, ei prosessori tied,  onko kyseess 
    8-  vai 16-bittiset muistiarvot ja luvut.  Tm on kerrottava prosesso-
    rille  erikseen.   Jos osoitetaan 8-bittist lukua  osoitteessa  1234h, 
    kytetn  muodon  [1234]  sijasta  muotoa   BYTE PTR [1234].  Etuliite 
    BYTE PTR kertoo,  ett kyseess on tavun (byte)  mittainen luku eli  8-
    bitti   pitk  luku.   Jos  osoitetaan  16-bittist  lukua  muistissa, 
    kytetn  muotoa  WORD PTR [1234],  joka kertoo,  ett luku  on  sanan 
    (word)   mittainen eli 2 tavua eli 16  bitti pitk.  Halutessamme siis 
    list  muistissa,  osoitteessa 4567h olevaan 16-bittiseen lukuun luvun 
    207h, kytmme komentoa ADD WORD PTR [4567],0207 

    Yhteenlaskun  lhin  sukulainen vhennyslasku toimii  samalla  tavalla, 
    paitsi  siin lhde vhennetn kohteesta ja tulos sijoitetaan  kohtee-
    seen. Vhennyskomento on SUB (SUBtract) ja se on muotoa 

    SUB <kohde>,<lhde>

    samalla tavalla kuin ADD-komentokin. SUB-komennolle ptee samat snnt 
    kohdetta ja lhdett koskien kuin ADD-komennollakin. 

    Kertolaskukomennon muoto on hieman erilainen kuin yhteen-  ja vhennys-
    laskukomennoilla. Komento on nimeltn MUL (MULtiply) ja sen muoto on: 

    MUL <lhde>

    MUL suorittaa kertolaskun, jossa toisena lukuna on annettu lhde, jonka 
    on oltava rekisteri tai osa muistia - suora lukuarvo ei kelpaa. Toisena 
    lukuna on aina akku eli rekisteri AX.  MUL-komento toimii 32-bittisell 
    prosessorilla (386  tai 486) kolmella tavalla,  mutta tss tutustutaan 
    vain kahteen, jotka toimivat kaikilla PC-koneilla. 
    
    TAPA  1:   Lhteen on 8-bittinen rekisterin puolikas kuten DH  tai  8-
    bittinen  pala  muistia.  Muistia osoittaessa on kytettv BYTE PTR  -
    etuliitett kuten ADD-komennossakin.  Tllin akun alempi puolikas (AL) 
    kerrotaan  lhteell ja tulos kirjoitetaan AX-rekisteriin  16-bittisen 
    lukuna. 

    TAPA 2: Lhteen on 16-bittinen rekisteri kuten DX tai 16-bittinen pala 
    muistia.  Muistia osoittaessa on kytettv WORD PTR -etuliitett kuten 
    ADD-komennossakin.  Tllin koko akku (AX) kerrotaan lhteell ja tulos 
    kirjoitetaan  32-bittisen  lukuna siten,  ett eniten merkitsev  sana 
    (ensimmiset  16   bitti)   kirjoitetaan  rekisteriin  DX  ja  vhiten 
    merkitsev sana (jlkimmiset 16 bitti) kirjoitetaan rekisteriin AX. 

    Esimerkki tavasta 1:

    MOV AL,13
    MOV BH,F3
    MUL BH

    AL kerrotaan BH:lla, saadaan 13h * F3h = 1209h. Desimaalijrjestelmss 
    sama  toimitus olisi 19d * 243d = 4617d.  Kertolaskuoperaation  jlkeen 
    rekisteriss AX on luku 1209h, joka on laskun tulos. 

    Esimerkki tavasta 2:

    MOV AX,1302
    MOV CX,A244
    MUL CX

    AX  kerrotaan  CX:ll,  saadaan 1302h * A244h = 0C0C5088h.   Desimaali-
    jrjestelmss  sama  toimitus  olisi  4866d  *  41540   =   202133640. 
    Kertolaskun jlkeen rekisteriss DX on tuloksen eniten merkitsev  sana 
    eli 0C0Ch ja rekisteriss AX on vhiten merkitsev sana eli 5088h. 

    Lopuksi vilkaistaan jakolaskua.  Komento DIV (DIVide) toimii kuten MUL. 
    Sen muoto on 

    DIV <lhde>

    ja sekin toimii kahdella tavalla (kolmella tavalla 386:lla ja 486:lla). 

    TAPA  1:   Kun lhde on 8-bittinen rekisteri tai pala muistia  (muistia 
    osoittaessa oltava etuliite BYTE PTR),  jaetaan AX:n sislt lhteell. 
    Osamr   sijoitetaan  alempaan  AX:n  puolikkaaseen  eli  AL:n   ja 
    jakojnns sijoitetaan ylempn puolikkaaseen eli AH:hon. 

    TAPA   2:   Kun  lhde  on  16-bittinen  rekisteri  tai  pala   muistia 
    (etuliitteen  oltava  WORD PTR),  jaetaan lhteell 32-bittinen  luku, 
    jonka ensimmiset 16  bitti eli eniten merkitsev sana on rekisteriss 
    DX ja viimeiset 16  bitti eli vhiten merkitsev sana rekisteriss AX. 
    Osamr sijoitetaan rekisteriin AX ja jakojnns rekisteriin DX. 

    Esimerkki tavasta 1:

    MOV AX,4C52
    MOV CL,25
    DIV CL

    Laskutoimitus  on  siis 4C52h / F9h = 4Eh jakojnns 74h.   Desimaali-
    jrjestelmss  19538d / 249d = 78d jakojnns 116d.  Nyt siis  lytyy 
    AL:st osamr 4Eh ja AH:sta jnns 74h. 

    Esimerkki tavasta 2:

    MOV DX,177A
    MOV AX,03E7
    MOV CX,A771
    DIV CX

    Laskutoimitus on 177A03E7h / A771h = 23E4h jakojnns 7043h Desimaali-
    jrjestelmss 393872359d / 42865d = 9188d jakojnns 28739d  Osamr 
    23E4h on rekisteriss AX ja jakojnns 7043h on DX:ss. 

    Koska  32-bittinen luku,  joka saadaan tavan 2  kertolaskussa  tuloksi, 
    ilmaistaan  samalla  tavalla  kuin 32-bittinen jaettava tavan  2  jako-
    laskussa, saadaan seuraavalla operaatiolla 

    MOV AX,1382
    MOV CX,1741
    MUL CX
    DIV CX

    AX:n alkuperinen luku 1382h.  DX:ss oleva luku on osamr,   mutta 
    koska jako menee luonnollisesti tasan, on kyseinen luku nolla. 

    Otetaan  nyt  pieni ohjelmaesimerkki  matematiikkakomentojen  kytst. 
    DOS:in  versionumeron  saa ktevsti nkyviin  kirjoittamalla  komento-
    riville  VER.  Mutta mit jos haluaisimme tiet versionumeron  jostain 
    .BAT-tiedostosta   ksin?   Jos  jokin  ohjelma  esimerkiksi  tarvitsee 
    toimiakseen  DOS  verison  4.0  tai  myhemmn,   voisi  .BAT-muotoinen 
    asennusohjelma  itsestn tarkistaa versionumeron,  mikli jokin  pieni 
    ohjelma voisi palauttaa sen ERRORLEVELin.  Errorlevel voi saada arvoja 
    vlill 0-255. Nykyn suurin DOS verisonumero on 6.jotain,  joten emme 
    voi  yksinkertaisesti  kertoa  verisonumeroa  sadalla  -  sit  ei  voi 
    ERRORLEVELin  ksitell.  Mutta voimme toki tyyty  kertomaan  versio-
    numeron  kymmenell ja jttmn mahdollisen desimaalin pois -  esimer-
    kiksi   DOS 3.31:n   versionumero  palautuisi  ERRORLEVELin  arvona  33 
    (3.31  *  10 = 33.1 josta jtetn desimaali pois).  Kykin niin onnel-
    lisesti,  ett on olemassa ers DOS-keskeytys,  jolla saadaan  selville 
    versionumero. Kyseess on keskeytys INT 21h, AH = 30h. Se palauttaa AL-
    rekisteriin pversionumeron eli ennen pilkkua tulevan numeron,  ja AH-
    rekisteriin alaversionumeron eli pilkun jlkeen tulevan numeron.   Voi-
    simme siis kertoa pversionumeron kymmenell,  jakaa  alaversionumeron 
    kymmenell hylten jakojnnksen, ja ynnt tulokset yhteen. Nin: 

    C:\>debug                   ;Kynnistetn DEBUG
    -a100                       ;Aletaan osoitteesta 100h
    0BC2:0100 mov ah,30         ;Kytetn INT 21h funktioa AH=30h
         0102 int 21            ;Nin ikn
         0104 mov cl,0a         ;Halutaan jakaa ja kertoa kymmenell
         0106 mov ch,ah         ;Alaversionumero talteen
         0108 mul cl            ;Pversionumero (AL:ss) kerrotaan 10:ll
         010A mov dl,al         ;Pversionumero*10 talteen
         010C mov al,ch         ;Alaversionumero ksittelyyn
         010E div cl            ;Alaversionumero jaetaan 10:ll
         0110 add al,dl         ;Listn tulokseen PVnumero*10
         0112 mov ah,4c         ;AH=4C, AL=ERRORLEVEL, INT 21
         0114 int 21            ;lopettaa ohjelman
         0116                   ;Palataan DEBUG:in komentotasolle
    -ngetver.com                ;Nimeksi GETVER.COM
    -rcx                        ;Mrtn sen pituus
    CX 0000
    :16                         ;0116h - 0100h = 16h
    -w                          ;Tallennus levylle
    Writing 00016 bytes
    -q                          ;Poistutaan DEBUG:sta
    C:\>                        ;DOS:in kehote.

    Nyt  on  valmiina  ohjelma,  joka  palauttaa  ERRORLEVELin  kymmenell 
    kerrotun  versionumeron,   josta on desimaalit  karsittu.   Seuraavalla 
    sivulla on pieni .BAT  -ohjelma, joka arvostelee  koneesi dossia GETVER
    -ohjelman palauttavan versionumeron perusteella..  todella hydyllist, 
    mutta nytt kyll, miten se toimii. 

    echo off
    getver
    if errorlevel 70 goto novautsi
    if errorlevel 60 goto juupajuu
    if errorlevel 50 goto kivadossi
    if errorlevel 40 goto melkovanha
    echo Sika vanha dossi, hanki uus.
    goto end
    :novautsi
    echo Vautsi mika dossi, 7.0 tai uudempi!
    goto end
    :juupajuu
    echo Onko DOS 6.jotain kiva kytt?
    goto end
    :kivadossi
    echo Jees, mullakin on DOS 5!
    goto end
    :melkovanha
    echo Eik DOS 4 ole jo aika vanha dossi?
    :end

    Nyt  alkaa  tm  kurssi olla edennyt yli puolenvlin.   Tmn  jlkeen 
    ilmestynee  viel ainakin yksi osa CyberDyne Magazinessa.  Sen  jlkeen 
    jokainen  saa  hankkia itselleen todellisen assemblerin  ja  todellisen 
    oppikirjan  ja  alkaa  vaan  koodaamaan  symbolista  konekielt!   Ensi 
    numerossa jatkuu... 

                                                            -Antti Niskanen


