Tm tiedosto on koottu CyberDyne Magazine:ssa ilmestyneen
'Assy Ohjelmointikurssi' -sarjan kolmannesta 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 kolmas osa===============================================
=====Ilmestyi numerossa 11/94==============================================

                        ͻ
                         Ŀ Ŀ Ŀ     
                         Ĵ Ŀ Ŀ Ĵ 
                                
                         OHJELMOINTIKURSSI OSA 3 
                        ͼ
    Minulle on esitetty toivomus,  ett tm ohjelmointikurssi  julkaistai-
    siin mys ASCII-tiedostoina, jotta sen voisi printata opiskelua varten.
    Olen  itsekin tllaista suunnitellut,  ja tarkoitus on tehd nin heti,
    kun  tm kurssi tulee ptkseen.  Koska mielenkiintoa lytyy jo  nyt,
    olen  jo  muuttanut kaksi ensimmist osaa ja tmn osan  tekstitiedos-
    toiksi,   jotka lytyvt CyberDyne:n "Programming"   -alueelta  nimell
    assy1.zip,   assy2.zip  ja  assy3.zip.  Kun koko kurssi  on  ilmestynyt
    lehdess,  nm tiedostot kasataan yhdeksi tiedostoksi,  joka laitetta-
    neen samalle alueelle.

    Edellisiss  jaksoissa  olemme jo perehtyneet  konekielisten  ohjelmien
    rakenteeseen  jonkin verran,  ja tunnemme muutaman kytetyimmn proses-
    sorikskyn. Nill kskyill psee jo hyvin pitklle. Muut kskyt ovat
    lhinn jononksittelykskyj ja matematiikkakskyj, joihin tutustumme
    mys  tss kurssissa.  Tss osassa emme kuitenkaan opi enem kskyj
    vaan sovellamme jo tuntemiamme kskyj.

    Ensimmisess osassa tt kurssia luettelin PC:n keskusyksikn rekiste-
    reit,  ja olemme jo kyttneet ns. tietorekistereit AX, BX, CX ja DX.
    Tiedmme,   ett  niit kytetn tiedon vliaikaiseen silytykseen  ja
    niiden  kautta annetaan parametriarvot keskeytyksille,  joita kutsutaan
    INT-kskyll.   INT-kskyn  palautekin sijoitetaan  tietorekistereihin.
    Mit ne muut rekisterit siis ovat? CS, DS, ES ja SS ovat ns. segmentti-
    reksitereit.   Niiss  silytetn  muistin  segmenttiosoitteita.   CS
    tarkoittaa Code Segment,  se kertoo prosessorille,  miss muistisegmen-
    tiss  on seuraava suoritettava ksky.  SS on Stack Segment ja  kertoo,
    miss pino sijaitsee (emme ole viel puhuneet pinosta).  DS  tarkoittaa
    Data Segment ja se kertoo,  mihin muistisegmenttiin kirjoitetaan tietoa
    tai mist sit luetaan. ES on Extra Segment, jota kytetn mys tiedon
    kirjoittamiseen ja lukemiseen sek jono-operaatioihin.

    Tm ei viel kerro kovin paljoa, ellen kerro, mik on muistisegmentti.
    PC:n  muistia  osoitetaan  kahdella luvulla:   segmenttiosoitteella  ja
    siirrososoitteella. Siirrososoite ilmoitetaan 16-bittisen lukuna, joka
    voi  saada arvoja vlill 0000-FFFF,  kymmenjrjestelmss 0  -  65535.
    Siirrososoitteella  voidaan siis osoittaa 64  kilotavua muistia.  Koska
    harvempi meist kytt en kuusnelosta,  ei 64  kB riit  alkuunkaan.
    Tt varten kytetn segmenttiosoitetta. Segmenttiosoite kertoo, miss

    pin muistia on siirrososoitteen 0000 osoittama kohta.  Jos ajattelemme
    muistia   lukusuorana  ja  siirrososoitetta  65535:n  tavun  mittaisena
    viivottimena,   ilmoittaa segmenttiosoite,  mihin kohtaan  lukusuoralla
    viivottimen nollakohta asetetaan.  Fyysinen muistiosoite saadaan,   kun
    kerrotaan  segmenttiosoite  kuudellatoista ja  listn  siirrososoite.
    Heksadesimaalijrjestelmss  kuudellatoista (10h)  kertominen  voidaan
    suorittaa  lismll luvun pern nolla samaan tapaan kuin  kymmenjr-
    jestelmss listn nolla kymmenell (10d) kertoessa. Tllin segment-
    tiosoitteesta   0040h  ja  siirrososoitteesta  0017h  saadaan  fyysisen
    muistin osoitteeksi 417h ( 0040h * 10h + 0017h = 00417h ).  Kyttmll
    segmenttiosoitetta  yhdess  siirrososoitteen  kanssa  voidaan  muistia
    osoittaa aina yhteen megatavuun asti.

    Tss  vaiheessa  voisi huomauttaa,  mikli lukija ei ole jo itse  sit
    huomannut,   ett  samaa  muistiosoitetta voi osoittaa  useammalla  eri
    tavalla.   Jos  vhennetn segmenttiosoitetta yhdell  ja  kasvatetaan
    siirrososoitetta 16:lla, saadaan sama fyysinen muistiosoite. Esimerkik-
    si  0040:0017  on sama kuin 0039:0027.   (Muistiosoitteet  kirjoitetaan
    siten, ett ensin kirjoitetaan segmenttiosoite,  sitten  siirrososoite.
    Luvut  erotetaan  toisistaaan kaksoispisteell ja molemmat  luvut  ovat
    heksadesimaalia.)

    Jokohan  nyt alkaa valjeta,  mik on esimerkiksi CS-rekisterin tehtv?
    Se kertoo prosessorille seuraavan suoritettavan kskyn  segmenttiosoit-
    teen...   eik  olisi loogista olettaa,  ett jokin rekisteri  kertoisi
    seuraavan  suoritettavan  kskyn  siirrososoitteenkin?   Aivan  oikein,
    rekisteri IP (Instruction Pointer)  tekee juuri tmn.  Ja hyppykomento
    JMP  suorittaa segmentin sisisen hypyn  kirjoittamalla  IP-rekisteriin
    uuden  arvon.  Jos ohjelma on yli 64  kB pitk,  voidaan  kytt  FAR-
    tyyppisi   hyppyj,   jotka  hyppvt  muistisegmentin  ulkopuolelle.
    Tllin kirjoitetaan sek IP- ett CS-rekisteriin uudet arvot. Ohjelman
    suoritus jatkuu eri muistisegmentiss.  Tllaisia hyppyj ei kuitenkaan
    .COM-tyyppisiss  ohjelmissa voi kytt,  joten jtmme ne sen suurem-
    mitta huomioitta. Vastaavasti on olemassa rekisteri SP (Stack Pointer),
    joka  kertoo  yhdess SS-rekisterin (Stack Segment)  kanssa,  miss  on
    pinon seuraava vapaa kohta. Siihen, mik se pino sitten on,  emme viel
    sen tarkemmin paneudu.

    Segmenttirekisterill  CS  siis kerrotaan,  miss  segmentiss  pyriv
    ohjelma tai sill hetkell aktiivinen osa ohjelmaa on.  Ents DS,  Data
    Segment  -rekisteri?   Katsotaanhan,  miten  MOV-kskyll  kirjoitetaan
    muistiin. Yksi tapa on seuraava:

        MOV [1234],AX

    Se  kirjoittaa rekisterin AX sislln muistiosoitteeseen 1234h.  Huomaa
    hakasulut.  Ne kertovat,  ett 1234  ei ole suora lukuarvo vaan muisti-
    osoite. Vastaavasti

        MOV AX,[1234]

    lukee rekisteriin AX muistiosoitteen 1234h sislln.  Huomaa hakasulku-
    jen  trkeys:   ilman hakasulkuja komento  kirjoittaisi  AX-rekisteriin
    luvun  1234h,  hakasulkujen kanssa se kirjoittaa AX:n  mink  hyvns
    luvun, joka on sill hetkell tallennettuna muistiosoitteessa 1234h.

    Tss  vaiheessa  lukijan  tulisi jo automaattisesti  kysy,   mik  on
    skeisten   komentojen   kyttmn   muistiosoitteen   segmenttiosoite?
    Muistiahan   osoitetaan  siirrososoitteella  ja   segmenttiosoitteella.
    Siirrososoite   on  hakasuluissa  annettu  1234h,   ja  segmenttiosoite
    puolestaan on...  ylltys ylltys...  DS-rekisteriss oleva  segmentti-
    osoite! Jos DS-rekisteriin kirjoitetaan 0040h, edell mainitut komennot
    lukevat ja kirjoittavat muistiosoitteeseen 0040:1234.

    Mihin  segmenttiin pitisi siis kirjoittaa?  Jos haluan tallentaa luvun
    muistiin, mist tiedn sellaisen osoitteen, joka on vapaana? Miten voin
    olla  varma,  etten vahingossa kirjoita sellaiseen osoitteeseen,  jossa
    onkin  itse  ohjelma?   Tllinhn ohjelma melko  varmasti  jumiutuisi.
    DEBUG:lla ohjelmoitaessa tuskin tulee tehty niin isoja ohjelmia,  ett
    ne veisivt enemmn tilaa kuin 64  kB.  Tllin riitt yksi muistiseg-
    mentti.   Jos katsot jotain edellisist ohjelmistamme,  huomaat,   ett
    missn  vaiheessa ei mritelty CS-rekisteri eik IP-rekisteri.  Kun
    ohjelma  kynistetn,  se ladataan muistiin ja CS-rekisteri saa itses-
    tn arvon,  joka osoittaa siihen muistisegmenttiin,  jossa ohjelma on.
    Mys  IP  saa automaattisesti oikean arvon  (joka  on  .COM-tyyppisill
    ohjelmilla  aina  0100h,   mink  takia  alammekin  aina  kirjoittamaan
    ohjelmia  osoitteesta 0100h).  Tllin prosessori  automaattisesti  saa

    tiet,   miss  on  ensimminen suoritettava komento.   Ainakin  .COM-
    tyyppisiss  ohjelmissa DS-rekisteri saa ohjelmaa  kynnistess  saman
    arvon  kuin  CS-rekisteri,  eli se osoittaa  siihen  muistisegmenttiin,
    johon itse ohjelmakin on ladattu. Jos emme muuta DS-rekisteri,  kaikki
    luku ja kirjoitus muistiin tapahtuu siin segmentiss,  miss ohjelmam-
    mekin  on.  Ei siis ole vaaraa,  ett kirjoittaisit  vahingossa  sinne,
    miss koneen kyttjrjestelm on ladattuna, mutta oman ohjelman plle
    on toki mahdollista kirjoittaa. Tt tuleekin varoa.

    Muistisegmenttihn on 64 kB lohko tietokoneen muistia. Sinne me yritm-
    me  mahduttaa sek ohjelmiemme tarvitseman datan,  ett itse  ohjelman.
    Ensimmiseen 256 tavuun ei voi kirjoittaa,  ne on varattu kyttjrjes-
    telmn  kytettvksi.   Seuraavat tavut ovat  osa  ohjelmaamme  (tavut
    osoitteesta 0100h = 256d eteenpin).  Kun ohjelmamme loppuu,  on kaikki
    loppu  muisti samassa segmentiss tyhj tilaa.  Tnne  siis  kannattaa
    sijoittaa  ohjelman  tarvitsema data.  Koska DS  saa  itsestn  oikean
    arvon,   j meidn huoleksemme vain oikean siirrososoitteen  antaminen
    muistia luettaessa ja sinne kirjoittaessa. Kuten hyppykskyj tehdess,
    kannattaa   kirjoittaa  vaikkapa  0100h  kaikkiin  muistia  osoittaviin
    komentoihin,  kirjoittaa ohjelma loppuun ja sitten palata kirjoittamaan
    oikeat  muistiosoitteet,  kun tiedmme,  miss ohjelma loppuu ja  miss
    vapaa, kytettviss oleva muisti alkaa.
 
    Tss  osassa ohjelmointikurssia emme kuitenkaan viel ryhdy kyttmn
    muistia  tiedon  silyttmiseen vaan  tutkimme  segmenttirekisterin  DS
    kytt.  Ohjelmaesimerkiss kytkemme  Caps Lock:in ja Num Lock:in pois
    plt ohjelmasta ksin.

    Konekieliohjelmoinnissa on paljon asioita,  jotka tytyy vain "tiet".
    Yksi nist asioista on, miten knnetn Num Lock tai Caps Lock plle
    ja pois.  Tm tapahtuu muistin kautta.  Erss tietyss kohdassa PC:n
    muistia on yksi ainoa tavu,  jonka kahdeksan bitti kertovat nppimis-
    tn kahden Shift-nppimen,  Ctrl-nppimen ja Alt-nppimen jokahetki-
    sen  asennon  sek Num Lock:in,  Caps Lock:in ja Scroll Lock:in  tilan.
    Tm  tavu  sijaitsee osoitteessa 0040:0017.  Seuraava taulukko  kertoo
    tavun kunkin bitin toiminnan:

        ͻ
       Bitti  Toiminta                       
       
         7    Insert-tila                    
         6    Caps Lock -tila                
          5    Num Lock -tila
          4    Scroll Lock -tila
         3    Alt-nppimen tila             
         2    Ctrl-nppimen tila            
         1    Vasemman Shift-nppimen tila  
         0    Oikean Shift-nppimen tila    
        ͼ
    Tavun bitit on siis numeroitu nollasta seitsemn. Seitsemn on korkein
    eli eniten merkitsev bitti eli MSB (Most Sensitive Bit).  Bitti  nolla
    on vhiten merkitsev bitti eli LSB (Least Sensitive Bit).  Kukin bitti
    voi  olla  ykknen tai nolla.  Jos kyseinen bitti  on  yksi,   kyseinen
    toiminto on aktiivinen,  toisin sanoen Caps Lock tai Num Lock on pll
    tai Ctrl-  tai Alt-nppin on sill hetkell painettuna.  Jos  jotenkin
    onnistuisimme  muuttamaan bitin 6 nollaksi,  menisi Caps  Lock  samalla
    pois plt, jos se on pll. Jos taas saisimme sen muutettua ykksek-
    si,   menisi  Caps Lock plle. Vastaavasti Num Lock:illa.  Koko  tavua
    voimme  toki muuttaakin.  Mutta jos haluamme kytke vaikkapa Num Lockin

    pois  plt muuttamatta Caps Lock:in tilaa,  on meidn voitava manipu-
    loida yksittist bitti. (Kuulostaa jo geenitekniikalta ja DNA-manipu-
    laatiolta!)  Luemme ensiksi koko tavun johonkin vapaaseen  rekisteriin,
    esimerkiksi  AL:n (AL on yhden tavun mittainen rekisteri.   AX  olisi
    sanan  mittainen eli kaksi tavua,  siis liian iso  meidn  kyttmme).
    Voisimme kytt komentoa

        MOV AL,[0017]

    mutta se ei toimisi. Haluamamme tavu on nimittin toisessa segmentiss.
    Ensin  meidn on kirjoitettava DS:n oikean segmentin osoite.  Kokeil-
    laan komentoa

        MOV DS,0040

    ja DEBUG ilmoittaa, ettemme voi tehd niin. Mihinkn segmenttirekiste-
    riin  ei voi suoraan kirjoittaa arvoa,  en tosin jaksa ymmrt,  miksi
    nin on. Kaikki arvot, mit sinne sijoitetaan on kirjoitettava vaikkapa
    jonkin tietorekisterin tai pinon kautta. Kytmme siis rekisteri.

        MOV AX,0040             ;Kirjoitetaan AX:n segmenttiosoite
        MOV DS,AX               ;Ja siirretn se sielt DS:n.
 
    Tll kertaa DEBUG hyvksyi ohjelmamme, ja DS-rekisteriin siirtyy oikea
    segmenttiosoite 0040h kun ajamme ohjelman.  Tst lhtien kaikki,  mit
    luemme  tai kirjoitamme muistiin,  kytt segmenttiosoitteenaan  lukua
    0040h,   joka on segmenttirekisteriss DS.  Vasta kun kirjoitamme uuden
    arvon  DS:n  tai kun ohjelmamme pttyy,  muuttuu DS:n arvo  joksikin
    muuksi.   Jos siis haluamme lukea AL:n osoitteessa 0040:0017   olevan
    arvon, kytmme komentosarjaa

        MOV AX,0040
        MOV DS,AX
        MOV AL,[0017]

    Jotta voisimme muuttaa yksittisen bitin nollaksi tai ykkseksi, meidn
    on tutustuttava AND ja OR kskyihin. Tutki seuraavaa kaaviota:

            0 1 0 1 0 1 0 1
        and 0 0 0 0 1 1 1 1
             01010101b and 00001111b = 00000101b
            0 0 0 0 0 1 0 1

    AND-operaattori  antaa  tuloksen tietyn bitin arvoksi 1  jos  KUMMANKIN
    lhteen vastaava bitti on 1. Muussa tapauksessa tuloksen kyseinen bitti
    asetetaan  nollaksi.  AND-operaatiolla voimme siis muuttaa  yksittisi
    bittej nolliksi muuttamatta muita bittej kyttmll toisena lhteen
    maskia, joka koostuu lhinn ykksist, mutta jossa on asetettu nollik-
    si  ne  bitit,  jotka halutaan muuttaa nolliksi.  Esimerkiss  muutimme
    luvun 01010101b nelj ensimmist bitti nolliksi vaikuttamatta neljn
    viimeiseen bittin kyttmll maskina lukua 00001111b.

    Jos  haluamme muuttaa tietyt bitit ykksiksi muuttamatta muita bittej,
    kytmme OR-operaatiota:

           0 1 0 1 0 1 0 1
        or 0 0 0 0 1 1 1 1
              01010101b or 00001111b = 01011111b
           0 1 0 1 1 1 1 1

    OR-operaattori  antaa tuloksen tietyn bitin arvoksi 1 jos  JOMPI  KUMPI
    TAI MOLEMMAT lhdebitit ovat ykksi.  Muuten bitin arvoksi annetaan 0.
    OR-operaatiolla voimme muuttaa yksittisi bittej ykksiksi koskematta
    muihin bitteihin.

    Konekieless AND-  ja OR-operaatiot saadaan aikaan kskyill AND ja OR.
    Niiden syntaksit ovat seuraavat:

        AND <kohde>,<lhde>

        OR <kohde>,<lhde>

    AND  suorittaa  loogisen AND-operaation kohteen ja lhteen  suhteen  ja
    kirjoittaa tuloksen kohteeseen.  Vastaavasti OR suorittaa OR-operaation
    kohteen ja lhteen suhteen ja kirjoittaa tuloksen kohteeseen.

    Nyt lienee jo kaikille pivn selv,  miten muutamme AL:n  lukemamme
    tavun yksittisi bittej nolliksi koskematta muihin. Olkoon tarkoituk-
    senamme kytke sek Caps Lock ett Num Lock pois plt.  Yritmme siis
    muuttaa AL:n kaksi bitti nolliksi muuttamatta muita bittej. Haluamam-
    me  bitit ovat bitit numero 6 ja 5,  sill ne ohjaavat aiemmin esitetyn
    taulukon mukaan Caps Lock:ia ja Num Lock:ia.  Kytmme siis AND-operaa-
    tiota ja maskia 10011111b (nollat ovat bittien 6 ja 5 kohdalla):

        bitin numero:  7  6  5  4  3  2  1  0
       
              bitti:  1  0  0  1  1  1  1  1
 
    Meidn on vain muutettava binriluku 10011111b  heksadesimaaliluvuksi,
    sill DEBUG ei hyvksy binrilukuja. Useimmat kehittyneemmt assemble-
    rikntjt  tosin  hyvksyvt  niitkin.  Monissa  taskulaskimissa  on
    mahdollisuus   muuttaa  binrilukuja  heksadesimaaliluvuiksi.    Ksin
    prosessi on hieman hankalampi.

        bitin         bitin arvo   bitin arvo
       numero  bitti  desimaalina  heksadesimaalina
     
          7      1    1*2^7 = 128  80h
          6      0    0*2^6 = 0    00h
          5      0    0*2^5 = 0    00h    ^-merkki
          4      1    1*2^4 = 16   10h    tarkoittaa
          3      1    1*2^3 = 8    08h    "potenssiin"
          2      1    1*2^2 = 4    04h
          1      1    1*2^1 = 2    02h
          0      1    1*2^0 = 1    01h
                                   
                      yhteens: 159 = 9Fh

    Tarvitsemamme  bittimaskin 10011111b arvo heksadesimaalilukuna on  siis
    9Fh.   AND-operaatio,  joka muuttaa AL:n bitit 6 ja 5 nolliksi tapahtuu
    siis konekielisell kskyll

        AND AL,9F

    Nyt  AL-rekisteriss  on tavu,  joka ilmaisee nppimistn  senhetkist
    tilaa,  paitsi ett Caps Lock ja  Num Lock ovat nyt pois plt.  Jotta
    nppimistn uusi  tila  tulisi voimaan,  on meidn vain  kirjoitettava
    uusi tilatavu takaisin sinne,  mist alkuperisen tilatavun otimme, eli
    osoitteeseen 0040:0017.  Koska  DS-rekisteriss on yh sinne kirjoitta-
    mamme segmenttiosoite 0040h, riitt kun annamme kskyn

        MOV [0017],AL

    ja  nppimistn  mahdollisesti pll olevat Caps Lock ja Num  Lock  -
    valot sammuvat. Tehtv on suoritettu, ohjelma on vain lopetettava. DS-
    rekisterin  arvosta meidn ei tarvitse vlitt,  se saa  kyll  oikean
    arvon  kun seuraava ohjelma ajetaan,  joten ei haittaa mitn,   vaikka

    olemmakin  muuttaneet  sen  arvoa tss ohjelmassa  palauttamatta  sit
    ennalleen.   Kytmme ohjelman lopettamiseen vanhaa tuttua  keskeytyst
    numero 21h, AH:n arvolla 4Ch:

        MOV AH,4C
        INT 21

    Ohjelma on nyt valmis.  Silt varalta, ett DEBUG on yh hieman hmr-
    perinen,  nytn koko prosessin alusta loppuun.  Keltaiset ovat tieto-
    koneen tulostamaa, valkoiset ovat minun kirjoittamia komentoja, vihret
    ovat kommentteja, niit ei kirjoiteta lainkaan.

    C:\>debug                   ;Kynnistetn DEBUG
    -a100                       ;Kirjoitetaan ohjelmaa osoitteeseen 0100h
    0F71:0100 mov ax,0040       ;Haluttu segmanttiosoite AX:n
    0F71:0103 mov ds,ax         ;Ja sit kautta DS:n
    0F71:0105 mov al,[0017]     ;Haetaan nppimistn tilaa kuvaava tavu
    0F71:0108 and al,9f         ;Muutetaan bitit 6 ja 5 nolliksi
    0F71:010A mov [0017],al     ;Ja kirjoitetaan se alkuperisen tilalle
    0F71:010D mov ah,4c         ;Ja poistutaan ohjelmasta
    0F71:010F int 21            ;vanhalla tutulla tavalla.
    0F71:0111                   ;Tyhj rivi palauttaa DEBUG:in komentotasolle
    -rcx                        ;Ilmoitetaan ohjelman pituus, joka saadaan
    CX 0000                     ;vhentmll 0100h tyhjn rivin siirros-
    :11                         ;osoitteesta. 0111h-0100h = 0011h
    -nlocksoff.com              ;Nimeksi tulee LOCKSOFF.COM
    -w                          ;Kirjoitetaan levylle
    Writing 00011 bytes
    -q                          ;Poistutaan DEBUG:sta.

    C:\>                        ;DOS:in kehoite, hhh!

    Nyt testataan: laita Caps Lock ja Num Lock plle ja kirjoita LOCKSOFF.
    Painaessasi enteri Num Lock:in ja Caps Lock:in valot sammuvat. Kirjoi-
    ta jotain ja kokeile nuoli/numeronppimi. Huomaat,  ett Caps Lock ja
    Num Lock todellakin ovat pois plt.  Laita nyt vain Caps Lock  plle
    ja aja LOCKSOFF.  Caps Lock sammuu ja Num Lock pysyy sammuksissa. Aivan
    kuten  halusimmekin.   Pienen DEBUG:in kytn  harjoituksena  muutamme
    ohjelmaa siten,  ett se laittaakin Caps Lock:in ja Num Lock:in plle.
    Emme  kirjoita  koko  ohjelmaa uudestaan,  vaan meidn  tarvitsee  vain
    muuttaa ksky

        AND AL,9F

    kskyksi

        OR AL,60

    sill  OR-komento  muuttaa  bitit  6  ja  5  ykksiksi  maskin  ollessa
    01100000b,  joka heksadesimaalimuodossa on 60h. Kopioimme ensin tiedos-
    ton DOS:sta ksin komennolla

        COPY LOCKSOFF.COM LOCKSON.COM

    ja teemme muutosen LOCKSON.COM:iin DEBUG:lla.

    C:\>debug lockson.com
    -u100                       ;Katsotaan, millainen ohjelma on muistissa
    0F96:0100 B84000        MOV     AX,0040
    0F96:0103 8ED8          MOV     DS,AX
    0F96:0105 A01700        MOV     AL,[0017]
    0F96:0108 249F          AND     AL,9F       ;<== Tt rivi haluamme
    0F96:010A A21700        MOV     [0017],AL   ;    muuttaa. Sen osoite on
    0F96:010D B44C          MOV     AH,4C       ;    0108h
    0F96:010F CD21          INT     21
    0F96:0111 4D            DEC     BP          ;<== Tm ei en ole osa
    0F96:0112 0000          ADD     [BX+SI],AL  ;    ohjelmaamme. Nm ovat
    0F96:0114 0000          ADD     [BX+SI],AL  ;    ovat jmi ohjelmista,
    0F96:0116 0000          ADD     [BX+SI],AL  ;    jotka olivat muistissa
    0F96:0118 0000          ADD     [BX+SI],AL  ;    ennen meidn ohjelmaamme.
    0F96:011A 0000          ADD     [BX+SI],AL  ;    ne eivt aina ole edes
    0F96:011C 0000          ADD     [BX+SI],AL  ;    samanlaisia.
    0F96:011E 0000          ADD     [BX+SI],AL
    -a108                       ;Haluamme muuttaa ksky osoitteessa 0108h
    0F96:0108 or al,60          ;Tm on uusi ksky, joka sinne kirjoitetaan.
    0F96:010A                   ;Tyhj rivi palauttaa DEBUG:in komentotasolle
    -

    -u100                       ;Tarkistamme, ett muutos tapahtui oikein
    0F96:0100 B84000        MOV     AX,0040
    0F96:0103 8ED8          MOV     DS,AX
    0F96:0105 A01700        MOV     AL,[0017]
    0F96:0108 0C60          OR      AL,60
    0F96:010A A21700        MOV     [0017],AL
    0F96:010D B44C          MOV     AH,4C
    0F96:010F CD21          INT     21
    0F96:0111 4D            DEC     BP
    0F96:0112 0000          ADD     [BX+SI],AL
    0F96:0114 0000          ADD     [BX+SI],AL
    0F96:0116 0000          ADD     [BX+SI],AL
    0F96:0118 0000          ADD     [BX+SI],AL
    0F96:011A 0000          ADD     [BX+SI],AL
    0F96:011C 0000          ADD     [BX+SI],AL
    0F96:011E 0000          ADD     [BX+SI],AL
    -w                          ;Tallennamme ohjelman levylle
    Writing 00011 bytes
    -q                          ;Ja poistumme DEBUG:sta.

    C:\>

    Sammuta  Caps  Lock ja Num Lock ja aja uusi ohjelma LOCKSON.COM.   Sek
    Caps Lock:in  ett  Num Lock:in  valot  syttyvt.  Harjoituksena voisit
    vaikkapa kirjoittaa ohjelman, joka kytkee plle pelkstn Caps Lockin
    tai Num Lock:in.  Sinun tarvitsee vain laskea tarvittavien bittimaskien
    heksadesimaaliarvot  ja  muuttaa  AND- tai  OR-ksky  sen  mukaisesti.
    Kokeilemalla oppii!

    Seuraavassa  osassa ohjelmointikurssia opimme,  mik se pino sitten on.
    Opimme mys muutaman matematiikkakskyn. Siihen asti...

                                                            -Antti Niskanen

