Tm tiedosto on koottu CyberDyne Magazine:ssa ilmestyneen
'Assy Ohjelmointikurssi' -sarjan kuudennesta 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 kuudes osa====================================================
=====Ilmestyi numerossa 09/95==============================================



    AAAAASSSSSSSSSSYYYYYKKKKKUUUUURRRRRSSSSSSSSSSIIIII

        Assy Ohjelmointikurssi on nyt melkoisen muutoksen edess:   Toistai-
    seksi  olemme tutustuneet aivan alkeisiin ja tehneet joitain  mitttmn
    pieni  ohjelmia DOS:in mukana tulevalla DEBUG-ohjelmalla.   Nyt  siihen
    tulee loppu.  Viimeksi ilmestyneess kurssin osassa nytin,  mit hyty
    oikeasta Assembler-kntjst on DEBUG:iin verrattuna,  ja tst eteen-
    pin kaikki tll julkaisemani ohjelmat tulevat olemaan oikealle  kn-
    tjlle tehtyj,  ei DEBUG-ohjelmalle. Aion seuraavissa numeroissa esit-
    t  pari melko yksinkertaista pikku hytyohjelmaa,  joilla  demonstroin
    Assembler-ohjelmointia.  Harjoitustehtvn,  mikli kiinnostaa,   kukin
    lukija  saa suunnitella parannuksia ja tehd muutoksia  ojelmiini,   tai
    kytt niiden koodia omissa projekteissaan.

        Kaikki ohjelmakoodi,  jota tulen esittmn on minun itse suunnitte-
    lemaani  ja  annan luvan kytt sit mihin tarkoitukseen  hyvns.   En
    kuitenkaan  ole  vastuussa  mistn  mahdollisista  vahingoista,   joita
    ohjelmien  ja niiden palasten kytst,  vrinkytst tai niihin  teh-
    dyist  muutoksista koituu - kaikki kyttvt niit omalla  vastuullaan.
    Olen  kuitenkin testannut valmiit ohjelmat omalla koneellani ja todennut
    ne toimiviksi.

        Monella DOS-kyttjll on varmaan joskus tullut vastaan  seuraavan-
    lainen tilanne:  Jokin suuremman kokoluokan ohjelma vaatii  toimiakseen,
    ett  ennen sen kynnistmist tehdn oletushakemistoksi se  hakemisto,
    jossa se sijaitsee.  Tai kenties se ajon aikana muuttaa oletushakemistoa
    joksikin muuksi kuin se oli alkujaan,  eik palauta sit en ennalleen.
    Tulos  on se,  ett ohjelman ajon jlkeen ei en olla samassa  hakemis-
    tossa kuin ennen ajoa. Ja jos ohjelmaa kytt usein jonkin pienen asian
    hoitamiseen  kesken  muiden tehtvien,  voi  tm  yllttv  hakemiston
    muuttuminen olla varsin rsyttv. Ainakin minusta se on.

        DOS  ei anna mitn mahdollisuutta tallettaa oletushakemistoa siten,
    ett  esimerkiksi .BAT-tiedostoa ajaessa oletushakemisto ensin  tallete-
    taan, sitten ajetaan jokin ohjelma,  jonka jlkeen palautetaan ennalleen
    se  oletushakemisto,  joka on talletettu.  Tss Assy ohjelmointikurssin
    osassa  aion  demonstroida,   miten symbolinen konekieli  voittaa  tmn
    ongelman hyvin siististi ja yksinkertaisesti.

        Hahmotetaan ensin ongelma. Tarvitaan tapa tallentaa oletuslevyaseman
    ja oletushakemiston nimi jonnekin, ja tapa kaivaa se jlleen esiin sinne
    palaamista varten. Yksi tapa, varmasti helpoimmasta pst,  olisi luoda
    tiedosto,  jonne oletusaseman ja -hakemiston nimet kirjoitettaisiin,  ja
    josta se voitaisiin mys lukea.  Mutta oletushakemiston  palauttamiseksi
    ei  vlttmtt  tarvita  omaa ohjelmaansa - jos  annetaan  tiedostolle,
    jonne  hakemiston nimi tallennetaan,  nimeksi vaikkapa GOTODIR.BAT,   ja
    tallennetaan sinne oletusasema ja -hakemisto muodossa:

        x:
        CD \xxxxxxxxxxxx

    Tllin  riitt,  ett ensin ajetaan hakemistonimen tallentava ohjelma,
    sitten  muutetaan  oletushakemistoa,   ajetaan  sovellus,   ja   ajetaan
    GOTODIR.BAT,   jolloin  oletushakemisto  ja  oletuslevyasema  palautuvat
    ennalleen. Nyt on vain suunniteltava se tallennusohjelma...

        Kun on tarkoitus luoda pieni tiedosto,  on jrkevint kert  kaikki
    sinne tuleva tavara muistiin ja kirjoittaa se kerralla tiedostoon.

        Tiedosto, jonka haluamme tuottaa nyttisi suunnilleen tlt:

            x:
            CD \xxxxxxxxxxxx

        Siin ei kuitenkaan ole kaikki,  mit tiedostoon pitisi tulla. Kum-
    mankin rivin lopussa tulisi olla rivinvaihto, eli merkit 0dh ja 0ah,  ja
    koko  tiedoston  lopussa olisi oltava tiedoston loppumisesta  ilmoittava
    merkki 1ah. Jrkevint olisi varmaankin sisllytt ohjelmaamme 'luuran-
    ko'   tulevasta  .BAT-tiedostosta,   jossa on kaikki  muuttumaton tavara
    valmiina,   ja johon vain lismme oletuslevyaseman kirjaintunnuksen  ja
    oletushakemiston nimen. Tllainen luuranko voisi olla tllainen:

    ranko:  db      ' :',0dh,0ah,'CD \'
    jotain:

    ranko: on tavallinen nimi, johon voimme viitata muualta ksin ohjelmas-
    samme.   Nm  viittaukset Assembler-kntj  muuttaa  muistiosotteiksi
    ohjelmaa  knnettess.   DB on ohje kntjlle,  ett sit  seuraavat
    merkit eivt ole ohjelmakoodia,  joka tulee knt konekielelle,   vaan
    dataa,   joka tulee sisllytt ohjelmaan sellaisenaan.   Heittomerkkien
    vliss oleva tavara tulkitaan sellaisenaan,  pilkuin toisistaan erotel-
    lut  heksadesimaalinumerot puolestaan muutetaan niit  vastaaviksi  mer-
    keiksi ohjelmaa knnettess.  Huomaa, kuinka olen vlilynnill varan-
    nut tulevalle levyaseman tunnuskirjaimelle tilaa kaksoispisteen  edess.
    Koko luurangon jlkeen tulee viel oletushakemiston nimi,  toinen  rivin
    vaihto ja loppumerkki.

        jotain:  on toinen tavallinen nimi, joka osoittaa seuraavaan vapaa-
    seen kohtaan muistissa. Sit tarvitaan myhemmin.

        Pienten .COM-ohjelmien perss on yleens riittvsti vapaata  muis-
    tia  ohjelman ajon aikana tarvittavan datan silytykseen.  Niinp  onkin
    loogisinta sijoittaa nimi ranko:  sit seuraavine roinineen koko ohjel-
    man loppuun.

        Nyt itse ohjelman kimppuun.  Ensimmiseksi on tietysti  selvitettv
    oletuslevyasema. Siihen kytetn DOS-kutsua INT 21h ja toimintoa numero
    19h  (Get current drive).  Mist tmn sitten tiet?  Listoja eri  DOS-
    toiminnoista  lytyy  riittmiin  alan  kirjallisuudesta.   DOS-toiminto
    numero 19h kutsutaan nin:

            mov     ah,19h
            int     21h

    ja se palauttaa AL-rekisteriin oletuslevyaseman numeron (0 = A:, 1 =  B:
    jne).   Tarkat tiedot eri DOS-toimintojen  palauttamasta  informaatiosta
    lytyy mys alan kirjallisuudesta.  Nyt meill on siis  oletuslevyaseman
    numero tiedossa.  Miten se muutetaan kirjaimeksi? Erittin helppo homma.
    Koska  0 vastaa A-kirjainta,  meidn on vain listtv AL-rekisteriin A-
    kirjaimen  ASCII-koodi,   niin AL-rekisteriss on oletusaseman  kirjain.
    Esimerkiksi jos AL:ss on luku 2 (C-asema),  ja sinne listn A-kirjai-
    men ASCII-koodi 41h,  saadaan tulokseksi 43h, joka on C-kirjaimen ASCII-
    koodi! Elikk:

            add     al,41h             ; 41h on A-kirjaimen ASCII-koodi!

        ranko: nimi osoittaa sit seuraavan datan ensimmiseen tavuun,  eli
    juuri  siihen,  mihin haluamme oletusaseman kirjaimen kirjoittaa.  Joten
    kirjoitetaan se sinne:

            mov     byte ptr [ranko],al

        Helppo homma. Nyt seuraa toinen helppo homma, oletushakemiston nimen
    selvittminen.  Siihen soveltuu DOS-toiminto 47h. Luku 47h siis sijoite-
    taan AH-rekisteriin.  Lisksi toiminto 47h vaatii,  ett DL-rekisteriss
    on  halutun  levyaseman numero,  ja ett DS:SI osoittaa  siihen  kohtaan
    muistia, johon oletushakemiston nimi kirjoitetaan. Asemien numerointi on
    nyt tosin hieman eri (1 = A:, 2 = B: jne), ja aseman numero 0 tarkoittaa
    oletuslevyasemaa. Kytetn siis lukua 0. Nin ikn:

            mov     ah,47h                  ; toiminnon numero
            mov     dl,0                    ; asema 0 = oletuslevyasema
            mov     si,offset jotain        ; siirrososoite
            int     21h                     ; DOS-kutsu.

        Huomaa, kuinka edellisess meidn oli mriteltv vain siirrososoi-
    te SI-rekisteriin, sill .COM-ohjelmissa DS-rekisteri osoittaa automaat-
    tisesti samaan segmenttiin, miss ohjelma (ja tss tapauksessa mys sen
    data) on.

        Yleisin  tapa silytt muistissa merkkijonoja on siten,  ett jonon
    lopussa on nollamerkki eli NUL,  jonka ASCII-koodi on 0.  Tll  tavalla
    DOS-toiminto  47h kirjoittaa muistiin oletushakemiston nimen.  Mutta  me
    haluammekin sen pttyvn nollamerkin sijasta rivinvaihtoon (merkit  0dh
    ja 0ah)  sek tiedoston lopetusmerkkiin 1ah. Lisksi meidn on tiedett-
    v,   kuinka monta tavua kirjoitamme GOTODIR.BAT -tiedostoon.   On  siis
    etsittv,   miss  nollamerkki oikein luuraa.  Siihen  voidaan  kytt
    erst  ns.   jononksittelyksky,  joka etsii tietty merkki  merkki-
    jonosta.  Tm ksky on SCASB (SCAn String Byte),  jota kytmme  REPNE-
    etuliitteen kanssa (REPeat while Not Equal).

            push    ds                      ; Sijoitetaan ES-rekisteriin
            pop     es                      ; oikea segmenttiosoite.
            mov     di,offset jotain        ; Etsint alkaa tst.
            mov     cx,128d                 ; Korkeintaan 128 merkki.
            mov     al,0                    ; Etsitn ASCII-koodia 0.
            cld                             ; Etsitn eteenpin.
            repne scasb

        Tm  nytt  ehk hieman sekavalta,  sill siin on  paljon  uusia
    komentoja.   Homma on oikeastaan aika yksinkertainen ja tysin looginen.
    SCASB-komento  vertaa  toisiinsa AL-rekisteri  ja  muistin  osoitteessa
    ES:DI olevaa merkki.  Sitten DI-rekisteri kasvatetaan yhdell.  REPNE-
    etuliite  puolestaan  toistaa SCASB-komentoa ja pienent  CX-rekisteri
    kunnes vertailtavat merkit ovat samat, tai CX tulee nollaksi.  Siksi CX-
    rekisteriin asetetaan ensin 128,  joka on riittvn iso,  ett nollatavu
    varmasti lytyy ennen kuin CX tulee nollaksi.  PUSH DS ja POP ES  yksin-
    kertaisesti  siirtvt ES-rekisteriin saman segmenttiosoitteen kuin  DS-
    rekisterisskin  on.   CLD-komento  kertoo SCASB-komennolle,   ett  DI-
    rekisteri on kasvatettava joka vertailussa.  Jos sen tilalla olisi STD,
    DI-rekisteri pienennettisiin joka vertailussa.

        Kun skeinen koodiptk on ajettu,  ES:DI osoittaa muistissa  nolla-
    tavua  seuraavaan merkkiin.  Haluamme korvata nollatavun luvulla 0dh  ja
    kirjoittaa  sen  pern  luvun 0ah.   DI-rekisteri  osoittaa  nollatavua
    seuraavaan  tavuun,  joten 0dh kirjoitetaan osoitteeseen [DI-1]  ja  0ah
    osoitteeseen [DI]. Loppumerkki 1ah tulee osoitteeseen [DI+1]. Nin:

            mov     al,0dh
            mov     [di-1],al
            mov     al,0ah
            mov     [di],al
            mov     al,1ah
            mov     [di+1],al

    Kuten muistanet kurssin alkuajoilta,  muistiin ei voi suoraan kirjoittaa
    numeroarvoa,   vaan se on kirjoitettava ensin rekisteriin ja siirrettv
    sit kautta muistiin.

        Nyt  olemme,   suunnitelmiemme mukaisesti,   kirjoittaneet  muistiin
    kaiken  haluamamme,   ja meidn on en luotava tiedosto GOTODIR.BAT  ja
    kopioitava tuon muistialueen sislt siihen.

       Tiedostojen  ksittely  ei suoraan sanoen ole  aivan  aloittelevalle
    assembler-ohjelmoijalle  kaikkein sopivinta harjoittelua,  joten en  ky
    sit lpi kovin hirven yksityiskohtaisesti.

        Ensi luodaan tiedosto,  johon aiomme kirjoittaa. Sit varten on DOS-
    toiminto 3Ch. Se vaatii,  ett CX:ss on tiedoston ominaisuudet mrv
    'tiedostomre' (tss tapauksessa 0) ja ett DS:DX osoittaa nollatavuun
    pttyvn  tiedostonimeen.  Tt varten meidn on sisllytettv ohjel-
    maamme dataa, jossa tiedostonimi kerrotaan. Esimerkiksi nin:

            nimi:   db      'C:\GOTODIR.BAT',0

    Se kannattaa sijoittaa ohjelman loppuun,  ennen ranko:  nimit.  Koodi-
    ptk, joka luo tiedoston on tllin:

            mov     ah,3ch                  ; toiminto 3ch luo tiedoston
            mov     cx,0                    ; tiedostomre
            mov     dx,offset nimi          ; osoittaa tiedoston nimeen
            int     21h                     ; kynnist toiminnon

       Mikli  tiedoston  luonti jostain syyst  eponnistuu,   Carry-lippu
    asetetaan ykkseksi.  Tm kannattaa tarkistaa,  sill jos tiedostoa  ei
    voida luoda, ei ohjelmamme voi toimia, ja se kannattaa tllin lopettaa.
    Ehdollinen hyppyksky

            jc      ongelm

    hypp  ongelm:   nimin,  mikli Carry-lippu on  ykknen  (eli  mikli
    tiedoston  luonti  eponnistui).   Jos  tiedosto oli  jo  olemassa,   se
    korvautui tiedostolla, jonka pituus on nolla.

        Nyt avataan tiedosto sinne kirjoittamista varten DOS-toiminnolla 3dh
    (Open file) seuraavasti:

            mov     ah,3dh                  ; toiminto 3dh avaa tiedoston
            mov     al,32h                  ; avauskoodi (yleens 32h)
            mov     dx,offset nimi          ; osoittaa tiedoston nimeen
            int     21h                     ; kynnist toiminnon
            jc      ongelm                  ; mikli ei onnistu

    Kutsu palauttaa AX:ss niinsanotun tiedostokahvan. Se on trke.

       Jotta  voimme  kirjoittaa  tiedostoon,  on laskettava  montako  tavua
    tiedostoon  on kirjoitettava.  Viimeinen kirjoitettava merkki oli osoit-
    teessa di+1 joten ensimminen vapaa tavu sen jlkeen on di+2. Kirjoitta-
    minen  aloitettiin   osoitteesta  ranko,   joten  merkkej  on  yhteens
    di+2 - ranko kappaletta. Lasketaan, paljonko siit tulee:

            mov     cx,di
            add     cx,2
            sub     cx,offset ranko

    Saman asian ajaisi elegantimmin:  (tt muotoa kytn ohjelmalistuksessa
    artikkelin lopussa)

            mov     cx,di
            sub     cx,offset ranko - 2

    (Assembler-kntj tulkitsee 'offset ranko - 2' olevan yksi luku, jonka
    arvon se laskee ohjelmaa knnettess).

       Kirjoitustoiminto on numero 40h (Write file). Toimiakseen,  sille on
    kerrottava  tiedostokahva,   kirjoitettavan tiedon osoite  muistissa  ja
    montako tavua kirjoitetaan. Nin:

            mov     bx,ax                   ; Tiedostokahva BX:n
            mov     ah,40h                  ; 40h = kirjoita tiedostoon
                                            ; Tavujen mr on jo CX:ss
            mov     dx,offset ranko         ; Tavujen osoite
            int     21h                     ; Kynnist toiminnon.

    Nyt jos ilmaantuu jokin onglema tiedostoa kirjoittaessa,  ei voi mitn.
    Carry-flagia  ei kannata tarkistaa,  sill tiedosto on  suljettava  joka
    tapauksessa. Sulkeminen tapahtuu nin:

            mov     ah,3eh                  ; Toiminto 3eh sulkee tiedoston
                                            ; Tiedostokahva on jo BX:ss
            int     21h                     ; Kynnist toiminnon.

       Nyt tiedosto on kirjoitettu, mikli ongelmia ei ole ilmaantunut. Oli
    niin tai nin, ohjelman suoritus lopetetaan nyt.

    ongelm:                                 ; Tnne hyptn, jos tiedostoa
                                            ; ei voitu luoda tai avata.
            mov     ah,4ch                  ; Toiminto 4ch lopetaa ohjelman
            int     21h                     ; Kynnist toiminnon.

    Tss on nyt ohjelman loppupiste, joten data sijoitetaan thn.

    nimi:   db      'C:\GOTODIR.BAT',0
    ranko:  db      ' :',0dh,0ah,'CD '
    jotain:

        Ohjelma  on  nyt valmis!  Seuraavilla sivuilla on  ohjelman  listaus
    ehjn kokonaisuutena kaikkine lismausteineen, jotka mahdollistavat sen
    kntmisen ainakin TASM:lla.

    main    segment para 'code'             ; Nm ovat moskaa,
            org 0100h                       ; jotka TASM haluaa nhd
            assume cs:main                  ; ennen kuin suostuu toimimaan
    hiphei:

            mov     ah,19h                  ; Selvitt oletuslevyaseman
            int     21h
            add     al,41h                  ; Muutetaan numero kirjaimeksi
            mov     byte ptr [ranko],al     ; ja tallennetaan muistiin

            mov     ah,47h                  ; Selvitt oletushakemiston
            mov     dl,0                    ; asema 0 = oletuslevyasema
            mov     si,offset jotain        ; siirrososoite johon kirjoitetaan
            int     21h                     ; DOS-kutsu.

            push    ds                      ; Nyt etsitn, miss kohtaa
            pop     es                      ; on nollamerkki hakemisto-
            mov     di,offset jotain        ; nimess.
            mov     cx,128d                 ; Korkeintaan 128 merkki.
            mov     al,0                    ; Etsitn ASCII-koodia 0.
            cld                             ; Etsitn eteenpin.
           repne scasb                     ;

            mov     al,0dh                  ; Kirjoitetaan kohdalleen
            mov     [di-1],al               ; tarvittava rivinvaihto
            mov     al,0ah                  ; ja tiedostonloppumerkki
            mov     [di],al                 ;
            mov     al,1ah                  ;
            mov     [di+1],al               ;

            mov     ah,3ch                  ; toiminto 3ch luo tiedoston
            mov     cx,0                    ;
            mov     dx,offset nimi          ; osoittaa tiedoston nimeen
            int     21h                     ;
            jc      ongelm                  ; hyptn jos ei onnistu

            mov     ah,3dh                  ; toiminto 3dh avaa tiedoston
            mov     al,32h                  ;
            mov     dx,offset nimi          ; osoittaa tiedoston nimeen
            int     21h                     ;
            jc      ongelm                  ; Hyptn jos ei onnistu

            mov     cx,di                   ; lasketaan, montako merkki
            sub     cx,offset ranko - 2     ; kirjoitetaan levylle.
            mov     bx,ax                   ; Tiedostokahva BX:n
            mov     ah,40h                  ; 40h = kirjoita tiedostoon
            mov     dx,offset ranko         ; Osoite, jossa tavara on.
            int     21h                     ;

            mov     ah,3eh                  ; Toiminto 3eh sulkee tiedoston
            int     21h                     ;

    ongelm: mov     ah,4ch                  ; Ohjelman lopetus vlittmtt
            int     21h                     ; siit, syntyik ongelmia.

    nimi:   db      'C:\GOTODIR.BAT',0      ; Tiedoston nimi - SAA MUUTTAA!
    ranko:  db      ' :',0dh,0ah,'CD \'     ; Muu ohjelman data tulee tnne
    jotain:

    main    ends                            ; Tm on mys vain, jotta
    end hiphei                              ; TASM suostuu toimimaan.

        Ohjelma  voidaan tallentaa vaikkapa nimell SAVEDIR.ASM.  Se voidaan
    knt .COM-ohjelmaksi (mikli kytss on TASM) komennoilla:

            TASM -m2 SAVEDIR
            TLINK /t SAVEDIR

        Kun  nin  syntyv .COM-ohjelma ajetaan,  se tekee  C:\  hakemistoon
    tiedoston nimelt GOTODIR.BAT (Lhdekoodia muuttamalla tiedoston nimi ja
    hakemisto on helppo muuttaa).  Jos tmn jlkeen oletushakemistoa muute-
    taan, ja ajetaan sitten GOTODIR.BAT, palautuu oletushakemisto ennalleen!

        Jos  vaikkapa  ohjelma HOOPO vaatii,   ett  siirrytn  hakemistoon
    C:\HOOPO ennen kynnistyst, voisi HOOPO.BAT olla vaikkapa tllainen:

            @ECHO OFF
            SAVEDIR
            C:
            CD \HOOPO
            HOOPO
            CALL C:\GOTODIR.BAT
            DEL C:\GOTODIR.BAT

        Kuten  net,  hankalalta nyttv ohjelmointitehtv ei olekaan niin
    vaikea! Seuraavissa lehden numeroissa esittelen muutaman lis tllaisia
    ei-niin-kovin-vaikeita ohjelmia.  Melko pian lehden ilmestymisen jlkeen
    aion muuttaa  tmnkin artikkelin  tekstitiedostomuotoon, jotta ohjelma-
    listauksen kyttminen olisi mahdollisimman helppoa.


    Lehden seuraavassa numerossa jatkuu...                -Antti Niskanen


     Seuraavassa lehden numerossa jatkuu...       -Antti Niskanen

                           oho se tulikin kaksi kertaa.



