Pred tym, ako zacneme naostro, este niekolko malych poznamok.
Vsetky ukazky strojovych rutin s ktorymi sa tu stretneme, su po
syntaktickej stranke pisane tak, aby ste ich mohli bez
akychkolvek uprav rovno prepisat do znameho ladiaceho systemu
MRS - verzie 07 a vyssich. Tyka sa to najme sposobu pisania
navesti, operandov instrukcii a niekorych specifickych
pseudoinstrucii.
Rutinky budu urcene pre pocitac ZX Spectrum a s nim
kompatibilne typy, ale niekore jednoduchsie rutinky budete moct
vyuzit aj na inych pocitacoch s procesorom Z80.
Ak nepochopite, ako nejaka rutinka pracuje ani po stodvadsiatom
osmom precitani, nezufajte ale jednoducho si povedzte, ze proste
nejak funguje a vratte sa k nej o nejaky cas, ked budete
mudrejsi a skusenejsi. Ak ani potom nepochopite cinnost rutinky,
cely tento cyklus opakujte.
Samozrejme mozete do redakcie pisat akekolvek pripomienky a
dotazy ohladne tohto serialu. Napriklad ak sa vam bude zdat
prilis jednoduchy alebo prilis narocny, ak vas bude specialne
zaujmat nejaky problem, alebo ak ani po stodvadsiatom osmom
opakovani vyssie spominaneho cyklu nepochopite cinnost dakej
rutinky a budete chciet, aby bola vysvetlena podrobnejsie. Ak sa
rozhodnete napisat, oznacte list heslom "Programujeme v
assembleri II". Zvlast uvitame kriticke dopisy, ktore budu
obsahovat nejake navrhy na zlepsene tohto serialu.
No a mozeme zacat naostro.
Jednym z najjednoduchsich problemov v strojovom kode je presunut blok pameti dlhy len bajtov z adresy ad1 na adresu ad2. Ten, kto pozorne sledoval v minulych cislach Bitu serial "Programovanie v strojovom kode", hned vie, ze tento problem riesi instrukcia LDIR. Staci jej len do vhodnych registrov vlozit tieto udaje. Takze kompletny program na kopirovanie bloku bude vyzerat takto:
copy | ld | hl,ad1 | odkial ho treba presunut |
ld | de,ad2 | kam ho treba presunut | |
ld | bc,len | dlzka bloku | |
ldir | samotne skopirovanie | ||
ret | a nakoniec navrat. |
Instrukcia ret zabezpeci navrat do hlavneho programu, z
ktoreho ste tuto rutinku zavolali instrukciou call copy alebo
do nejakeho monitora (napriklad debugger v systeme MRS), ak ste
ju volali z tohto monitora alebo pripadne do basicu, ak ste ju
volali pomocou USR copy.
Ak by ste chceli skopirovat blok o nulovej dlzke, narazili by
ste na isty problem. Instrukcia LDIR totiz nulu v registri BC
chape ako hodnotu 65536 a aj tak dlhy blok sa bude snazit
skopirovat. No a ten problem je v tom, ze vam moze poskodit ine
programy, ktore mate v pameti (napriklad ten monitor).
Skusme teraz vymysliet rutinku, ktora nebude blok kopirovat,
ale ho zmaze, presnejsie povedane pametovu oblast od adresy
add s dlzkou len zaplny bajtami s hodnotou byte. Na prvy
pohlad sa zda zmazane bloku jednoduchsie ako jeho skopirovanie.
Ale na druhy pohlad zistime, ze neexistuje instrukcia ktora by
priamo vykonavala tuto cinnost.
Len tak na pripomenutie sa pozrime, ako vlastne pracuje
instrukcia LDIR. Vezme prvy bajt z adresy v registri HL, potom
tento bajt ulozi naspet do pameti, ale na adresu v registri DE.
Nakoniec obsahy registrov HL a DE zvecsi o 1, BC zmensi a ak sa
este BC nerovna nule, znovu zopakuje celu tuto cinnost.
Co sa ale stane, ak hodnota v registri DE bude prave o 1 vecsia
ako v HL ? Vezme sa bajt z adresy HL, ulozi sa na adresu DE,
potom sa prislusne zmenia hodnoty registrov a ak BC nie je este
nulove, cyklus sa opakuje. Nech este nie je nulove. Znovu sa
vezme bajt z adresy HL a ulozi sa na adresu DE... Stop ! Lenze
ten bajt, ktory sa teraz premiestnil, je vlastne presne ten, co
sme premiestnili v predchadzajucom cykle. No a v kazdom dalsom
cykle sa potom prenesie ten isty bajt, co v cykle tesne pred
nim. Toto sposobi "rozkopirovanie" jedneho bajtu po celej dlzke
bloku.
No a tak rutinka na zmazanie bloku moze vyzerat nejak takto:
zmaz | ld | hl,add | zaciatok bloku |
ld | de,add+1 | zaciatok zvecseny o jednu | |
ld | bc,len-1 | dlzka bloku zmensena o jednu | |
ld | (hl),byte | ulozenie prveho bajtu | |
ldir | skopirovanie dalsich bajtov | ||
ret |
Vsimnite si, ze do registra BC sa pise dlzka bloku zmensena o
jednotku. Je to tak preto, lebo prvy bajt bloku ulozi instrukcia
"ld (hl),byte" a preto ho samotna instrukcia LDIR uz nemusi
ukladat.
Kedze prvy bajt bloku sa uklada natvrdo a instrukcia LDIR vzdy
skopiruje aspon jeden bajt, je tato rutinka schopna mazat bloky
o dlzke aspon dva bajty. Co by sa stalo, keby sme aj napriek
tomu za hodnotu len dosadili jednotku ? Vsimnime si, ze v
registri BC je pri vstupe do instrukcie LDIR hodnota len-1. No
a z predchadzajuceho prikladu uz vieme, co sa vtedy stane.
Skopiruje sa (a teda vlastne zmaze) 65536 bajtov...
Keby ste nahodou za len dosadili nulu, potom v BC bude -1, co
predstavuje hodnotu 65535 a tolko bajtov sa aj vtedy zmaze.
Takze je to prakticky to iste...
Vas Busy.