Cikkek
Lehetőségek Páratlan Tárháza (LPT)
Tömbök rendezése
Betöltési problémák
Hanoi Tornyai
ENTERPRISE képviselet nyílt Budapesten
Az ismeretlen SPOKE és SPEEK
A közvetlen lemezkezelés rejtelmei
Az Enterprise DOS lemezek felépítése
Assemly segédrutinok
Sprite kezelés ENTERPRISE-on
RAM-szegmensek az EXOS alatt
A tömörített programokról (kiegészítve)
A bináris számokról
Cartridge átalakítások
Az életjáték
Karakterek tervezése
BASIC programok láncolása
Táblázatos Adatbevitel BASIC-ben
Microsoft BASIC programok futtatása Ep-n
A dBASE II adatbáziskezelő rendszer ismertetése
Címezzünk pontosan!
AZ ENTERPRISE rendszer-szegmens rögzített területének címei
és azok funkciója
Compfair '94
Billentyűzet és joystick olvasás
B0-B7, BF regiszterek értelmezése
Felhasználói megszakításkezelés
Az Enterprise memórialapjainak kezelése
EXOS kompatibilis memóriakezelés
Tisztelt Olvasó!
Az ENTERPRISE számítógép 1987 májusában tűnt fel a hazai áruházakban. Sokan döntöttünk a gép megvétele mellett annak ellenére, hogy igazából nem tudtuk, mi rejtőzik a fekete dobozban. Kevés volt a szoftver, a szakirodalom. Akkori hírek szerint az ENTERPRISE cég csődbement, a gép nyugaton csúfosan megbukott, és nekünk csak az olcsó "vas" jutott. A helyzet meglehetősen ellentmondásos és zavaros volt.
Aztán teltek-múltak a hónapok. Lassan megismertük gépünket, és rájöttünk, hogy az ENTERPRISE a maga kategóriájában kiváló számítógép. A hazai forgalmazó sok ígéretet tett, igyekezett ezeket teljesíteni, bennünket ellátni. Feltűntek a komoly, professzionális felhasználói és játékprogramok, igyekeztünk ezekhez hozzájutni (ki így, ki úgy). Megvásárolhattuk a régóta áhított szakirodalmat, leírásokat. A tehetősebbek lemezegységet, egeret, beszédszintetizátort vehettek.
Mára a helyzet sokat tisztult. Nem igazolódtak azok a feltevések, amelyek a gép helyzetét negatívan ítélték meg. Természetesen igaz, hogy az ENTERPRISE lemaradt az iparszerű szoftver-és hardverfejlesztésről, de rendelkezünk a továbblépéshez szükséges alapszoftverekkel, információkkal. A géptulajdonosok egy része programokat készít, kisebb-nagyobb áramköri kiegészítőket tervez és illeszt a géphez, sokfajta tapasztalattal rendelkezik. Nagy kár, hogy miután megszületik valami, az csak néhány közeli baráthoz jut el, vagy egyszerűen elsüllyed egy fiók mélyén. Pedig könnyen lehet, hogy néhány kilométerrel arrébb valakinek pontosan erre lenne szüksége.
Az ENTERPRESS kiadásával szeretnénk megteremteni az ENTERPRISE tulajdonosok közötti kapcsolatot. Tudomásunk szerint tizennyolcezer felhasználó dolgozik, játszik ENTERPRISE géppel, de ez a szám hamarosan eléri a húszezret. Egy ekkora tábor jogosan vár használható, értékes tudnivalókat. A hazai szaksajtóban már jelentek meg vele kapcsolatos cikkek, de az összes ilyen lapra jellemző, hogy az ENTERPRISE-zal csak mellékesen foglalkoznak.
Célunk, hogy az ENTERPRESS-t igazi házi számítógépesekhez szóló kiadvánnyá formáljuk. Többféle sorozatot szeretnénk elkezdeni, ezekben egy-egy témával részletesen megismerkedhetne az érdeklődő. Például: Z80 Assembly és az EXOS, Pascal, dBase, a grafika (sprite-ok) és a hang kezelése, hardverelemek ismertetése. A Basic nyelvvel kapcsolatos tanfolyamot nem szándékozunk közölni, hiszen erről már sok könyv jelent meg, mi inkább kész listákat, megoldásokat közölnénk több-kevesebb magyarázattal kiegészítve. Igyekezni fogunk a játékprogramokhoz leírásokat, térképeket, örökéletkódokat szerezni, bár ezzel a témával több kiadvány foglalkozik, és nehezen tudnánk velük konkurálni.
Természetesen a lapot az olvasók beküldött írásai, programjai, ötletei, tapasztalatai is színesítenék. Jó tollú szerzők akár sorozatot is indíthatnak, ezért honoráriumot fizetünk. Hosszabb programokról csak leírást fogunk közölni, ezek kazettára másolva lesznek megrendelhetők. Biztosan népszerű lesz a levelezési és a hirdetési rovat. (Már most felhívjuk a nepperek figyelmét, hogy ránk ne számítsanak!) A leendő szerzőkre vonatkozó tudnivalókat később közöljük.
Néhány mondat az ENTERPRESS helyzetéről: a lapot tavaly, karácsony előtt akartuk megjelentetni, de szerencsésen mindig közbejött valami. Az újság tulajdonosa a székesfehérvári Mátrix Kft. Mint gazdálkodó, nyereséget váró gazdasági szervezet, a lapot valamelyes hasznot hozó vállalkozásként kezeli. (Nem ettől fognak nagy céggé fejlődni!) Manapság a lapkiadás - mint minden más - meglehetősen kockázatos. Az ENTERPRESS további léte kizárólag a fogadtatás sikerétől függ. Kedvező esetben jelentősen növeljük a példányszámot, kialakítva az elérhető árat is.
Az ENTERPRESS első száma valószínűleg kevesekhez jut el. Szeretnénk remélni, hogy előbb-utóbb minél több géptulajdonos szerez tudomást lapunk létezéséről, és annak elolvasása után már türelmetlenül várja a kővetkező számot.
A szerkesztők (1990 szeptember)
Lehetőségek
Páratlan Tárháza (LPT)
Az eddig ENTERPRISE-a készült programok közül szinte csak a demókból kaphattunk
némi ízelítőt számítógépűek grafikai képességeiből. Pedig a számunkra felkínált
lehetőségek szinte korlátlanok. Ezeknek a látványos megoldásoknak a megismeréséhez
szeretnék némi segítséget nyújtani ebben a rovatban.
Először a LPT felépítését ismertetem, majd kisebb-nagyobb példaprogramokkal
próbálok bemutatni néhány bükköt, ötletet Természetesen ezek megértéséhez
illetve használatához ismerni kell a assembly programozás alapjait valamint
a ENTERPRISE memóriakezelését
Az ENTERPRISE grafikájáért a NICK chip felelős. A működésébe való beavatkozáshoz
négy port áll rendelkezésünkre. Ezen portok és szerepük a következő:
A NICK chip porijai után lássuk a memóriakezelését.
A NICK csak 64 kbájtot tud megcímezni, de azt közvetlenül teszi attól függetlenül,
hogy az be van-e lapozva vagy nincs. Ezt a grafikus memóriaterületet a felső
4 szegmens alkotja (0FCh..0FFh). Ezeket a Z80 aszerint címzi, hogy melyik lapra
vannak belapozva, a Nick azonban folytonosan 0000h-tól 0FFFFh-ig. A videómemóriához
való hozzáférésben a Nick chipnek prioritása van, ezért itt a programok lassabban
futnak és nem időzíthetők.
Minden LPT egyenként 16 bájtos sorparaméter blokkokból áll. Egy-egy LPB (Line
Parameter Block - sorparaméter blokk) a képernyőnek egy részét definiálja. Ennek
a képernyőrésznek MODSOR a neve. Egy sorparaméter blokk felépítése a következő:
Egy LPT definiálásához ismerni kell a TV-kép felépítését. A
teljes kép 625 sora két egyenként 312.5 soros félképből áll. Az egyik félkép
tartalmazza a páros sorszámú sorokat a másik a páratlanokat. Ahhoz tehát, hogy
a kép ne hullámozzon pontosan 312.5 sorból kell állnia a LPT által definiált
MODSOR-oknak. Ilyenkor a két félkép teljesen megegyezik egymással. Természetesen
lehetőség vas a teljes 625 soros képernyő kihasználásához. Ezt interlace üzemmódnak
hívják Ilyenkor az egyik félkép-definíció végén nem állítjuk be a RELOAD bitet,
hanem folytatjuk a második félképpel és csak ennek a végen utasítjuk a Nick-et,
hogy kezdje előröl a LPT olvasását.
A tökéletes állóképhez még egy dologra kell ügyelnünk, mégpedig a szinkronizációra.
A pixelsorok vízszintes szinkronizációját a gép elvégzi helyettünk, a függőleges
képszinkront azonban nekünk kell biztosítani. Ezt legegyszerűbben a következő
két LPB-vel tehetjük meg:
0FCh,10h,00h,3Fh,00,00,00,00,00,00,00,00,00,00,00,00
0FFh,10h,3Fh,20h,00,00,00,00,00,00,00,00,00,00,00,00
Szinkronizációs módban a bal és a jobb margó a szinkron be-illetve kikapcsolásának
a helyét vezérli a soron belül. Az első blokk négy pixelsort definiál (100h-FCh=04h).
Ezen LPB legelején bekapcsolódik a szinkronizáció és bekapcsolva is marad egészen
a második blokk feléig. Mivel a második LPB csak egy pixelsort jelent ezért
a szinkron összesen 4.5 sor idejére van bekapcsolva. Tehát még 312.5-4.5=308
sort kell definiálnunk.
A Nick minden sort 57 szakaszra oszt fel és minden szakaszban két bájtot tud
beolvasni. Az első nyolc szakaszban beolvassa a soron következő LPB-t Ezután
a beolvasott sorparaméter blokk alapján előállítja a aktuális képsort. A sor
a képernyőn a bal és jobb margó által meghatározott helyre kerül. Az utolsó
három szakaszban történik a videómemória frissítése. A bal margó legkisebb lehetséges
értéke tehát nyolc, a jobb margó pedig maximum 36h lehet A margókon kívül eső
terület keretszínű lesz.
A videómódokat 3 fő részre oszthatjuk. Ezek a grafikus mód, a karakteres és a szinkron üzemmód. A szinkron problémájával már foglalkoztunk, most lássuk a grafikus képmódokat. Ebből három féle áll a rendelkezésünkre: pixel, attributum és lpixel. A pixel és Ipixel módok között csak a vízszintes felbontásban van különbség, mégpedig a lpixel mód feleakkora felbontású mint a pixel. Így memóriát takaríthatunk meg, ha megelégszünk a kiesebb felbontással. Ezen videómódokban a képernyőbájtok jelentése a színmódtól függ:
A grafikus videomód harmadik tagja az attribútum mód.
Ezzel a képtípussal találkozhatunk legtöbbször a játékprogramokban, mivel a
ZX Spectrum csak ezt ismeri, és a legtöbb játékot Spectrum-ról konvertálták
át. Ezt a videomódot az ENTERPRISE programozók nem szívesen alkalmazzák, pedig
hátrányai mellet sok előnyös tulajdonsága is van. De vajon hogyan épül fel egy
attribútum kép?
A leglényegesebb hogy különválik a képpont- és a színterület. Az LPB-ben az
elsődleges videó adatcím (LD2) adja meg a képterület memóriacímét, a másodlagos
adatcím (LD1) pedig a színterület memóriacímét. A képpontok területe hasonló
a kétszínű üzemmód memóriaterületéhez, vagyis minden képpontnak egy bit felel
meg. Ha a bit beállított állapotú, akkor a bitnek megfelelő pont tintaszínű
lesz, ellenkező esetben papírszínű. Azt, hogy a papír és tintaszínek valójában
mit jelentenek, a színterületen adhatjuk meg. A képpont-memória minden bájtjához
tartozik ugyanis egy attribútum-bájt, amelynek felépítése a következő:
b0..b3 Tintaszín palettaszám. (0..15)
b4..b7 Papírszín palettaszám. (0..15)
Mint az a fentiekből is látható, az attribútum módban 16 szín használatára van
lehetőségünk, olyan felbontás mellett, mint amilyen a 4 színű pixel módé. Örömünk
azonban nem lehet teljes, mert egy képbájthoz csak egy attribútum-bájt tartozhat.
Ebből következően az egy bájtban lévő nyolc ponthoz csak két színből választhatjuk
ki az aktuálisat, hasonlóan a C64-es képkezeléséhez. A legnagyobb hátrány azonban
az attribútum mód használatakor az, hogy nincs olyan rajzolóprogram, amely megfelelően
kezelné azt. Még egy fontos dologra fel kell hívnom a figyelmet: az attribútum
videomódot kétszínű színmóddal kell használni, az LPB második bájtjának 14h-nak
kell lennie.
Ezzel a grafikus videómódok ismertetésének végére értünk, most
lássuk a karakteres képmódokat!
A karakteres üzemmódokból három féle áll a rendelkezésünkre, amelyek rendre
a következők: 256 karakteres (CH 256), 128 karakteres (CH 128) és 64 karakteres
(CH 64) mód. A három üzemmód csak a használható karakterek számában különbözik
egymástól. Mindhárom módban az LD1 tartalmazza a karakterkódok memóriacímét,
ahol a kijelzendő karakterek ASCII kódjait tároljuk. Az LD2 a karakterkészlet
kezdőcímét tartalmazza, elosztva az üzemmódban használható karakterek számával,
tehát CH 256 módban 256-tal, CH 128 módban 128-cal és CH 64 módban 64-gyel kell
osztani a karakterkészlet Nick-címét. A karakterkészlet felépítése a következő:
először a karakterek első bájtját tároljuk az ASCII kód szerinti sorrendben,
majd a másodikat és így tovább. Azt, hogy hány bájt (illetve pont) magas legyen
egy karakter, az LPB első bájtjával tudjuk beállítani, így 1 és 256 között bármilyen
magasságú karaktereket használhatunk. A karakterkészletben lévő bájtok a képernyőn
a színmódtól függően kerülnek megjelenítésre, hasonlóan a pixel grafikus módnál
megismertekhez. A különböző színű karakterek megjelenítéséhez az LPB-ben két
vezérlőbitet -nevezetesen az LS BALT-tot és az MS BALT-tor- használhatunk.
A színvezérlő-bitek használatát nem részleteztem, ezért
most ez következik.
Egy LPB-ben négy színvezérlő-bit található, ezek az ALTIND0, ALTIND1, LS BALT
és MS BALT nevet viselik. Az (eredeti) EXOS leírással ellentétben mindegyik színvezérlő-bit
mind karakteres, mind grafikus üzemmódban használható. Most nézzük meg részletesen
az egyes bitek jelentését!
Szeretnék néhány szót szólni a színekről, merthogy erről még nem volt szó.
Valószínűleg mindenki előtt ismert tény, hogy a TV-technikában a színek három
összetevőből - a vörös, a zöld és a kék színárnyalatok keverékéből - állnak.
Ugyanezt a módszert használják a számítógépek is. Az ENTERPRISE 8 árnyalatot
tud megkülönböztetni a vörös és a zöld színből és négyet a kékből. Ez alapján
könnyen kiszámolható, hogy összesen 8 x 8 x 4=256 színárnyalatot képes megjeleníteni.
Ahhoz, hogy egy színnek megállapíthassuk a kódját ismernünk kell a színkódok
felépítését. Ez a következő:
b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
G0 | R0 | B0 | G1 | R1 | B1 | G2 | R2 |
Ez egy bináris szám, ahol R a vörös, G a zöld, B a kék szint jelenti, a betűk melletti szám pedig a színerősség bináris értékének helyértéke. Például, ha 5-ös erősségű vöröset akarunk előállítani, akkor R2 R1 R0=101b vagyis a színkód 01010001b=81h. Ezek alapján már bármilyen szín kódját kiszámolhatjuk.
DEVIL - Enterpress 1990/2-1991/4
Tömbök rendezése
A számítógép - mint tudjuk - sok mindenre jó. Adatok, adatbázisok kezelésére
különösen. Egy ilyen állományban sokkal gyorsabban érhetünk el információkat,
ha a belsejében rend van. A karbantartó munkát valamilyen rendteremtő algoritmusra
kell bíznunk. Rengeteg ilyen létezik, mi ezek közül most a beszúrásos rendezéssel
(InsertionSort) ismerkedünk meg.
Összekevert számsort rendezünk növekvő sorrendbe. A beszúrásos módszer a következőket
teszi: mozgat egy mutatót, amely az éppen feldolgozás alatt álló adatra mutat.
A mutató a második pozíciótól az utolsó felé halad. Összehasonlítja a mutatónál
lévő adatot az előtte levő, eggyel kisebb sorszámú adattal. Amennyiben a kisebb
sorszámú adat értéke kisebb vagy egyenlő, mint az aktuális, akkor nincs semmi
tennivalója csupán a mutatót kell eggyel növelnie. Ellenkező esetben a mutatónál
lévő adatot megjegyzi, és elkezdi a mutató értékénél kisebb sorszámú adatokat
egy hellyel "jobbra" eggyel nagyobb sorszámú pozícióra mozgatni, az
aktuális mutatóértéktől lefelé a kisebb sorszámok felé haladva egészen addig,
amíg a megjegyzett adatnál kisebbet vagy azzal egyenlőt nem talál. Ekkor a megüresedett
helyre beírja a megjegyzett adatot, majd növeli a mutatót, és folytatja a rendezést.
A könnyebb érthetőség kedvéért nézzük a következő, félig már rendezett számsort:
Sorszám | 1. | 2. | 3. | 4. | 5. | 6. | 7. |
Adat | 15 | 27 | 53 | 21 | 77 | 22 | 15 |
Legyen a mutató értéke éppen 4. Összehasonlítja a 21-et a 53-mal. A 21 nyilván rossz helyen van, megjegyzi a számot. Elindítja az adatok mozgatását "jobbra" a 3. pozíciótól kezdve a csökkenő sorszámok felé, egészen addig, amíg a 21-nél kisebbet vagy azzal egyenlőt nem talál. A mozgatás befejezésekor a 21-et beszúrja a megfelelő helyre. A módosult sor:
Sorszám | 1. | 2. | 3. | 4. | 5. | 6. | 7. |
Adat | 15 | 21 | 27 | 53 | 77 | 22 | 15 |
Növeli a mutató értékét, így az az 5. adatra mutat. A 77 viszont nagyobb, mint az 53, tehát nincs semmilyen művelet, csak a mutatót kell növelnie. A rendezés véget ér, ha a mutató elérte a tömbhatárt, és az utolsó mozgatás is véget ért. Az algoritmust Basic-ben a listán látható program valósítja meg: Az "A" tömb elemeit a "TOLT" inicializálja,
a "KIIR" megjeleníti, a "REND" rendezi. Természetesen
a "REND" eljárás másik programban is használható, a tömbnek
új nevet, módosított hosszat is adhatunk. A legnagyobb tömbméretnek a
gép memóriája és szabad időnk nagysága szab határt. A programot 200 elemmel
próbáltam ki: a futási idő 4 perc 40 másodperc volt. Valószínű, hogy TURBO
ENTERPRISE-on valamivel jobb eredmények születnének. Enterpress 1990/1 |
|
Betöltési
problémák
Valószínűleg az összes EXDOS felhasználónak az volt az első dolga, amikor üzembe
helyezte lemezegységes rendszerét, hogy a kazettán lévő programjait átmásolta
lemezre. A Spectrum-ról átírt játékprogramok másolásánál valószínűleg nem is
volt sok gondja, csak a magnó lassúsága. Az eredeti ENTERPRISE játék- és felhasználói
programok nagy része azonban már több gondot okozott. Most az ilyen programok
lemezessé konvertálásához szeretnék néhány hasznos tanácsot adni.
A gép megjelenésekor még nem lehetett lemezmeghajtót illeszteni az ENTERPRISE-hoz,
ezért az akkor készült programok eleve magnós konfigurációhoz készültek. Átírás
szempontjából ezek a programok is több csoportba sorolhatók.
Általában minden programnak van egy betöltője, ami lehet egy rövid Basic program,
vagy egy gépi kódú, 5-ös fejléccel rendelkező, ún. új alkalmazói program (NAP=New
Application Program). Ez a betöltő elindulása után beolvassa a teljes programot,
majd átadja annak a vezérlést.
Ahhoz, hogy be tudjunk tölteni valamit, először meg kell nyitni egy csatornát
egy eszközre. Basic-ben ez egy
OPEN £csatorna:"eszköz:fájlnév"
utasítással lehetséges, ahol a csatorna a csatorna száma, az eszköz lehet TAPE:
a magnó esetében, a lemezegységnél pedig a meghajtó azonosítója. Ha nem írunk
eszköznevet, akkor a csatorna az alapértelmezésű eszközre fog vonatkozni, ami
alapkonfigurációnál a magnó. Ha a géphez lemezegységet csatlakoztatunk, akkor
az lesz az alapértelmezésben használt eszköz. Lehetőség van arra is, hogy fájlnevet
sem adunk meg, ekkor a magnós konfigurációnál a szalagon elsőnek megtalált fájlt,
lemeznél pedig a START nevű fájlt nyitja meg az EXOS.
A csatornanyitás gépi kódban sem sokkal bonyolultabb. Az A regiszterbe a csatornaszámot,
a DE regiszterpárta pedig a fájlnév memóriabeli kezdőcímét kell betölteni, és
végül egy EXOS 1 hívást kiadni. A fájlnév megadása hasonló, mint a Basic-ben,
azzal a különbséggel, hogy az első bájt a karakterfüzér hosszát adja meg bájtokban.
A két lehetőség keveredésével is találkozhatunk: a betöltő Basic nyelvű, de
gépi kódban történik a beolvasás. Ilyenkor a Basic program az ALLOCATE és CODE
utasításokkal előállít egy gépi kódú rutint, majd CALL USR utasítással meghívja
azt.
Az eddigi információk alapján már valószínűleg érthetővé válik az a jelenség,
amelynél egy lemezre másolt programot próbálunk betölteni, és az első blokk
után leáll a gép, amely aztán kazettáról akar olvasni, vagy egyszerűen lefagy.
Ha az első eset fordul elő -amikor kazettáról akar a gép olvasni-, akkor a csatornanyitásban
a TAPE: eszköznév szerepel. Ezen lehet a legkönnyebben segíteni, egyszerűen
át kell írni a TAPE: szöveget a program második fájljának nevére.
Ha a betöltő Basic és találunk benne egy OPEN £csatorna:"TAPE:..."
utasítást, akkor azt javítsuk ki úgy, hogy az idézőjelben csak a fájl neve szerepeljen.
Ha a betöltő gépi kódú, akkor töltsük azt be egy assemblerbe (célszerű az ASMON-t
használni, mert az megadja a töltés végcímét), és keressük meg a TAPE: stringet.
Ha megtaláltuk, javítsuk ki, de vigyázzunk rá, hogy a hosszbájt is jó legyen.
Basic-ből hívott gépi kód esetén a HEX$ függvény argumentumában kell megkeresnünk
az "54,41,50,45,3A" számsort, ami a TAPE: sztring ASCII megfeleltje
hexadecimális alakban. Ezt már könnyedén ki tudjuk javítani (itt is figyeljünk
a hosszbájtra).
A másik esetben nem is próbál a gép továbbtölteni, hanem csak lefagy. Ez akkor
fordul elő, ha a megnyitáskor sem eszköznév, sem pedig fájlnév nem volt megadva.
Magnónál ez nem gond, mert a soron következő fájl betöltődik. Az EXDOS azonban
megnézi, hogy van-e START nevű fájl a lemezen, és ha nincs, akkor egy hibakóddal
visszatér. Ez az eset Basic betöltőnél nem fordul elő. Gépi kódnál (Basic-ből
hívottnál is) meg kell keresni, hogy hol nyitja meg a csatornát a program. Ez
gépi kódban egy EXOS 1 hívást, hexa-dumpnál egy "F7 01" számsort jelent.
A hívás előtt mindig van egy "LD DE,cím" utasítás, ahol a "cím"
a fájl nevének memóriabeli kezdőcímével egyenlő. A hexa-dumpban ez a következőképpen
néz ki: "11 x1 x2", ahol az x1 az alsó, x2 a cím felső bájtja tehát
a cím=x1+256*x2. Ha cím által meghatározott memóriarész tartalmát megnézzük,
akkor látjuk, hogy ott egy 00 bájt szerepel. Általában itt nincs is akkora hely,
amelyen elférne a betöltendő fájl neve, így kell keresnünk valahol annyi üres
helyet a programban, ahol a név elfér (ha máshol nem, akkor a program végén).
Ide beírjuk a fájl nevét hosszbájttal az elején, majd azt a címet ahová írtuk,
beírjuk az "LD DE,cím" utasításba operandusként (xl, x2 helyére).
A gépi kódú programot az assemblerbe az l0F0h címre érdemes tölteni, így a programban
szereplő címek 1000h értékkel lesznek eltolva.
Ezek voltak az egyszerűbb esetek (már amennyire ez egyszerű lehet). Ezeknél
valamivel bonyolultabb a helyzet, ha nem egy fájlt tölt be a betöltő, hanem
többet és mindegyikhez ugyanaz a fajlnév van rendelve (ami lehet 00 is). Ebben
az esetben mindegyik csatornanyitásnál át kell írni a majdani fájlnevek kezdőcímeit
(ezek kerülnek DE-be) különböző értékekre (ott, ahol erre van hely a programban),
és az egyes címekre be kell írni a fájlneveket. Ilyenkor általában már csak
a program után van annyi helyünk, ahol ez elfér, tehát hosszabb lesz a betöltő.
Ha az 10F0h címre töltöttük a programot, akkor az 10F2h címen található a hossza,
amit át kell írni az új hosszértékre.
Ezeknél bonyolultabb esetek megoldására már csak a gépi kódú programozásban
jártasak vállalkozhatnak eredményesen. Ilyen eset az, amikor a program konkrét
memóriacímeket használ a rendszerszegmensben, vagy olyan memóriaterületet igénylő
video-csatornát akar megnyitni, amelyhez nincs elég hely, ugyanis az EXDOS lefoglal
kb. 4 kilobájtot. Ekkor a fájlok betöltése után elfelejtetjük a géppel a lemezegység
meglétét, amit a következő módon lehet elérni: a rendszerszegmensben az EXOS
ROM-ok táblázatot át kell írni úgy, hogy csak az 1-es és a Basic szegmens maradjon
meg. Az ABBDh címtől 0,0,0,0,1,0,0,0,x,0,0,0,0 számsort kell beírni ahol az "X" a Basic szegmens száma (angol gépnél 4, németnél 5), majd a BF95h
és a BF97h címre (a rendszerszegmensbe) ABBDh-t kell írni. Végezetül egy EXOS
0 hívást kall végrehajtatni a C regiszter 0 értéke mellett.
Az eddig felsorolt esetek a régebben (1985) készült programoknál fordultak elő.
Az újabb készítésű programokat - gondolok itt az "a" Studio és a Novotrade
programjaira - már szándékosan készítették úgy, hogy azok csak magnóról induljanak
el, ez ugyanis egyfajta programvédelemként szolgál.
Az egyik megoldás az, amikor a programot saját betöltővel látják el, így ezeket
a programokat az EXOS nem képes beolvasni. Ilyenek például az "EGGS OF
DEATH", a "MIRROR_WORLD" című játékprogramok. A megoldás az,
hogy a fájlokat a saját loaderükkel betöltjük, majd EXOS formátumban kimentjük.
A betöltőt pedig átírjuk olyanra, hogy az az EXOS-t használja beolvasásra a
speciális loader helyett.
A másik programvédelmi lehetőséget a "FINE PEN" sprite-tervező programnál
figyelhetjük meg. Az elv a következő a betöltő egy 6-os fejlécű abszolút rendszerbővítő,
amely a betöltődés után elindul. Korrekt működés helyett azonban végrehajt egy
EXOS 0 hívást, melynek hatására újrainicializálódik a beépített és bővítő perifériák,
valamint rendszerbővítők. Az alapperifériák után a rendszerbővítő ismét megkapja
a vezérlést, hogy inicializálódjon. Ehelyett ismét mást csinál: átveszi a vezérlést,
és elkezdi betölteni a főprogramot. Mivel csak az alapperifériák inicializálása
történt meg, ezért az EXOS nem tud róla, hogy lemezegység is van a konfigurációban.
DEVIL - Enterpress 1991/1.
A buddhista szerzetesek időtlen időkig üldögéltek templomaikban, igyekezve megoldani a Hanoi torony néven közismertté vált feladványt, biztosan tudva, hogy amint ez sikerül valamelyiküknek, igen nagy mennyei boldogság lesz az osztályrésze. A feladat lényege, hogy a réz rúdra 64 darab lyukas korong van feltéve, ezek mindegyike valamivel kisebb az alatta lévőnél. A 64 korongot át kell tenni az arany rúdra, de egyszerre csak egy korong mozgatható, és bármelyik korong mindig csak nála kisebb korongra tehető rá. Segítségképpen (egy mai szakember azt mondaná, pufferként) igénybe vehető az ezüstrúd. A feladat igen egyszerűnek látszik. Néhány ügyes mozdulattal sikerülhet is átpakolnunk 3, vagy akár 4 korongot is a szabályoknak megfelelően az aranyrúdra. Minél tovább megyünk azonban, annál kilátástalanabbnak tűnik a megoldás. Pedig nincs nagy vész, a 3 korongot 7 lépésben tudjuk átrakni, a 4 korongot 15 lépésben, az 5 koronghoz is csak 31 jól megválasztott lépés kell... Megállapíthatjuk, hogy n korong átrakásához (2^n)-1 lépés szükséges. |
![]() |
Mi már tudjuk, hogy a szegény szerzetesek igen reménytelen feladatba kezdtek.
A 64 korong átrakása ugyanis (2^64)-1,azaz mintegy 1,8*10^19 lépés szükséges.
Ez másként leírva 18446744073709551615 (vagyis az a maximális szám, amit 64 biten fel lehet írni). Ez olyan
nagy szám, hogy elképzelni is lehetetlen. Másodpercenként 1 áthelyezést végezve
éjjel-nappal, megállás nélkül, (86400*365,24 áthelyezés évente) kb. 585 milliárd év alatt végeznénk. Jó lesz hát sietni! Egy jó tanács: ne próbáljuk kivárni! A Föld "mindössze" 4,54 milliárd éves, és Nap 10 milliárd éves várható életkorának felénél járunk, mivel nagyjából még 5 milliárd évre elegendő a hidrogénkészlete a fúziós reakció táplálására.
Csak megjegyezzük, hogy véletlenül majdnem pont (2^64)-1 búzaszemet kapott
volna a monda szerint a sakkjáték feltalálója jutalmul,
ő a sakktábla minden mezejére kétszer annyi szemet kért, mint az előzőre. Az
ő jutalmát majdnem 3 millió, egyenként egymillió tonnás óriás tartályhajó tudná
elvinni...
A
program bemutatja a Hanoi torony feladat megoldásának egy részletét. A program
lényege a TORONY nevű rekurzív (azaz önmagát újra és újra meghívni képes) eljárás,
a többi csak díszlet. A program legfeljebb 13 korongot képes átpakolni, de ehhez
több mint 2 óra szükséges.
UL&BG - Enterpress 1991/2.
ENTERPRISE
képviselet nyílt Budapesten
A képviselet meglétéről szerkesztőségünk már tavaly augusztusban tudomást szereztünk,
hiszen a képviselet emberei hallva az ENTERPRESS készülődéséről, azonnal felkerestek
bennünket. Olvasóinkat erről azért nem tájékoztattuk eddig mert az augusztusi
találkozónk csak egy futó egyeztetés volt, igazából konkrét információkat még
nem tartalmazott.
Sajnos rögtön a cikk legelején el kell árulnunk, hogy még mindig nincs itt az
"ENTERPRISE kánnán": A VTGe Elektronikai Kft. - az ENTERPRISE Computers
GmbH magyarországi képviselete - nem üzletet, hanem csak egy irodahelyiséget
nyitott Budaörsön. Hogy pontosan mivel is foglalkoznak arra sok egyéb kérdésünk
mellett Kopácsy Vilmos ügyvezető igazgató válaszolt.
A Kft. mostanában leginkább a gépek Szovjetunióbeli elterjesztésével foglalkozik
- mondja Kopácsy úr - de az ottani belpolitikai helyzet miatt ez kissé vontatottan
halad. A szovjet partner a gép liszenszét szeretné megvásárolni, a gépet pedig
ottani alkatrészekből akarja összerakni. Úgy képzeli, hogy a gyártásnál mi csak
a háta mögött állnánk. Még a Dave-et és a Nick-et is ó akarja az alaplapra tenni.
- Hány gép van már a Szovjetunióban?
Pontosan nem tudom, de úgy háromezer körül lehet a számuk. A gépeket hálózatba
kapcsolva kazahsztáni iskolákban használják, és a gépek összerakása is itt folyna.
Nagyobb érdeklődés mutatkozik az ENTERPRISE PC-k iránt.
- Mitől lesz ENTERPRISE egy PC?
A PC-k alaplapját az ENTERPRISE cég tervezte, és az alaplapokat Németországban
készítik. Kínálatunk az XT termináltól kezdve egészen a 486-osig tart.
-Térjünk vissza a gépünkre! Úgy hallottuk, hogy Egyiptomban is van egy nagyobb
adag belőle.
Igen, ott a 64K-s változatból kelt el négyezer darab.
- Milyen új szoftvereket várhatnak a hazai felhasználók?
Az "a" Studio programozói pillanatnyilag 15 játékprogramon dolgoznak,
a Centrum megbízásából pedig 10 ilyen készül.
- És a játékprogramokon kívül készülnek-e más programok?
Most dolgozunk egy feliratozó szoftveren, amelyhez egy ún. genlocker kártya
is kell. Ez utóbbinak az a feladata, hogy a kamera és a számítógép képjelei
korrekt módon keverhetők legyenek. A számítógép és egy szintetizátor összekapcsolásához
szükséges Midi interfész és szoftver fejlesztése is folyik.
- Milyen újdonságok vannak még?
A 128K-s alapgéphez ma már akár 160MB-os merevlemez is kapcsolható. Elkészült
az az illesztőnk is, amellyel a PC-khez kapcsolható kártyák nagyrésze az alapgépbe
dugható. Így akár VGA monitort is kapcsolhatunk a konfigurációnkhoz.
- Mikor kezdik az új termékek árusítását?
A szoftver és a hardverfejlesztés egyelőre nem rentábilis. Amíg a régi készleteink
is megvannak, semmiképpen sem fogunk bele az árusításba.
- Mik ezek a régi készletek?
Főleg a 4000 darab Spectrum-emulátort és az SzJA'88 programot említhetném.
- Mekkora ennek a készletnek az összértéke, és hol van?
Összértékük ötvenmillió forint, és a Centrum raktáraiban vannak.
- Úgy hallottuk, hogy a Novotrade Rt. gondozásában megjelent "EXOS ROM0
visszafejtése" című könyvvel kapcsolatban valamilyen galiba volt...
Igen, a Novotrade kinti megbízottját beperelte az ENTERPRISE GmbH. Ez a megbízott
a harmadfokú tárgyalás után többszázezer márka kártérítést fizetett az ENTERPRISE-nak.
A ROM visszafejtésének közléséhez ugyanis az ENTERPRISE cég engedélye szükségeltetett
volna...
- Megbízható forrásból tudjuk, hogy a könyv szerzője már elkészült a 1. szegmens
visszafejtésével is. Ezek szerint ez nem fog megjelenni... Az ENTERPRESS az
olvasók kívánságának megfelelve szeretné a gép és az EXDOS kapcsolási rajzát
közölni. Mit szól ehhez?
Nem értem, hogy egy amatőrnek miért van szüksége a gép kapcsolási rajzára! Ez
a cég belső magánügye.
-Talán így még inkább fellendülnének a fejlesztések...
Aki kapcsolási rajzot akar szerezni a gépről, az már ezt bármelyik klubban megteheti.
Egy ilyet nekem is adtak, pedig tudták, hogy ki vagyok. Az ENTERPRESS egyébként
azt közöl amit csak akar, de vállalnia kell a következményeit is.
- Hmmm... Sok olvasónk panaszolja hogy gondjai vannak az EP-PLUS kártyával,
és hiába várnak választ az "a" Studio-tól.
Az "a" Studio-tól a VTGe Kft. hamarosan átveszi a leveleket, és mindegyikre
válaszolni fog.
- Készül-e új ENTERPRISE modell?
Igen, bár itt alapvetően az 128K továbbfejlesztéséről van szó. Az új modell
külsőleg leginkább egy lapos PC-hez hasonlítható, külső billentyűzettel. Alaplapján
lesz az EXDOS, be lesz építve a Midi interfész, és a hardveres hálózat kezelő.
Azt, hogy mekkora központi memóriája lesz, majd az akkori árak fogják eldönteni.
- Milyen processzorral és operációs rendszerrel lesz a gép felvértezve?
Valószínűleg a Hitachi Super Z80-asa lesz a gépben. Ennek a processzornak 21
bites címbusza van, és tartalmazza a matematikai kooprocesszort is. A gép operációs
rendszere pedig az EXOS 3.0-ás verziója lesz.
- Ez mit tud ?
Mindazt amit az EXOS 2.1-es változat. Ezenkívül jellemzője, hogy felhasználói
felülete csaknem teljesen grafikus, és a rendszer ikonvezérelt. A felület az
EGI (ENTERPRISE Graphics Interface) névre hallgat, és leginkább az Atari GEM-re
hasonlítható.
Szerkesztőségink nem állhatja meg hogy megjegyzéseit a cikk
végére ne írja. Mint ahogyan azt Kopácsy úr is mondta a fejlesztések nem hozzák
meg a kellő bevételt. Így nem várhatjuk, hogy a VTGe Kft. csupán emberbaráti
szeretetből elhalmoz bennünket jobbnál jobb hardver és szoftver termékekkel.
Az ENTERPRISE GmbH természetesen figyeli a magyarországi felhasználók sajátos
helyzetét, de igazán döntő lépéseket nem tud tenni.
A beszélgetés során rengeteg szakmai kérdést tettünk fel Kopácsy Vilmosnak aki
- lévén, hogy kisujjában van a gép - készséggel válaszolt ezekre. Ha egyébként
olyan olvasói kérdések érkeznek hozzánk, melyeket szerkesztőségünk nem tud megválaszolni,
akkor azokat átadjuk a képviseletnek.
Az új, fejlesztés alatt álló ENTERPRISE modellel kapcsolatban van néhány felvetésünk,
mindenféle rossz szándék nélkül. Bár nem tudjuk, hogy mikorra készül el a gép,
de ha már most sorozatgyártásban lenne, szerintünk már akkor is elkésettnek
számítana. Nem hisszük hogy a mind olcsóbbá váló PC-knek, Amigáknak Atariknak
komoly ellenfél lehet egy ilyen adottságú gép. A másik problémát pedig az új
gépre nem létező szoftverek okozzák majd.
Persze mi felhasználók már sokszor tapasztalhattuk, hogy az ENTERPRISE fronton
nehéz bármit is előre jósolni. Amíg van időnk és türelmünk, addig várjuk ki
ennek is a végét.
Enterpress 1991/2.
Az ismeretlen
SPOKE és SPEEK
Olvasóink kőzűl jónéhányan kifogásom hogy a kőzőlt programok egy részében magyarázat
nélkül haszná juk a SPOKE és a SPEEK utasításokat. Kicsit értetlenül fogadjuk
ezeket a kifogásokat, hisz nincs ezekben az utasításokban semmi különleges.
Szeretnénk azonban elejét venni a további zsörtölődésnek így most egy külön
cikket szentelünk e témának.
Gépünk 128KB-nyi RAM-mal rendelkezik, ezt a memóriát a gép tervezői 16KB-os
részekre, ún. szegmensekre osztották. A teljes RAM az alapkiépítésű gépben 8
darab ilyen szegmensre tagolódik. A prospektusokból megtudhatjuk, hogy a gép
maximálisan 4MB-os memóriát tud kezelni, ebbe a ROM és a RAM szegmensek egyaránt
beleértendők. A Z80-as CPU 64KB memóriát képes egyszerre kezelni, így a CPU-n
egy időben négy szegmens lóghat. A CPU a lapjain látja a szegmenseket. A lapok
mérete igazodik a szegmensek méretéhez, egy lap egy 16KB-os tartományt fed le.
A laptartományok:
0. lap: 00000-16383
1. lap: 16384-32767
2. lap: 32768-49151
3. lap: 49152-65536
A szegmensek cserélgetését memórialapozásnak, röviden csak lapozásnak nevezzük.
Fizikailag a lapozás egy meglehetősen komplex feladat, nem véletlenül szükséges
hozná egy külön, memórialapozó funkciókat (is) ellátó kooprocesszor, a Dave.
Basic-ból is van lehetőség a direkt memórialapozásra: a 176-179 portok tartalma
dönti el, hogy a CPU adott lapján melyik szegmens van. A 176-os port a 0. laphoz,
a 179-es port a 3. laphoz tartozik; az IN és az OUT utasításokkal e portok tartalmát
szabadon olvashatjuk, írhatjuk. (A 0. és a 3.lapokat lehetőség szerint ne zaklassuk!)
Minden szegmensnek saját azonosítószáma van, ezt szokás szegmensszámnak (vagy
nagyzolós körökben "szegmenscímnek") nevezni. Például az EXDOS vezérlőprogramja
a 32-es és a 33-as ROM szegmenseken helyezkedik el. Ha igazán jó programokat
akarunk készíteni, akkor a szegmensek számozását és szerepüket pontosan kell
ismernünk. Lehetetlenség lenne e cikk, de akár a teljes lap terjedelmében a
gépben lévő szegmenseket, feladatukat ismertetni, így ettől eltekintünk. Itt
most elegendő annyi ismeret, hogy az EXOS a RAM szegmenseket a 248-255 tartományba
sorolja, és a 255-ös szegmens az ún. rendszerszegmens. Az alapvető lehetőségeknél
(pl. gépi kód, POKE, PEEK) tudnunk kell, hogy melyik szegmensen és a szegmensen
belül melyik címen lévő adattal akarunk műveleteket végezni, és hogy mindezt
a CPU melyik lapján kívánjuk tenni.
A két utasítás (SPOKE, SPEEK) elsősorban a közvetlen memórialapozástól mentesít
bennünket. Basic-ben tehát elegendő a szegmensszámot, és a szegmensen belüli
címet az ún. ofszetcimet tudnunk, a tár állapotának könyvelésével (melyik szegmens
melyik lapon van stb.) nem kell foglalkoznunk.
A SPOKE (Segment POKE) paranccsal bájtot tudunk letárolni
egy adott szegmens ofszetcímére, az utasítás helyes formája:
SPOKE(szegmensszám,ofszetcím,érték)
A szegmensszám 0 és 255, az ofszetcím 0 és 16383, az érték 0 és 255 közötti,
illetve azzal egyenlő is lehet. Az ofszetcím helyére a megadottnál nagyobb értéket
is felvehetünk, az utasítás csak a cím alsó 14 bitjét veszi figyelembe. Így
ha például a SPOKE(200,0,0) helyett SPOKE(200,65536,0) írunk, ugyanazt az eredményt
kapjuk. Konkrét példaként színezzük át a képernyő első sorát a hagyományos POKE,
majd pedig a SPOKE utasítással!
Basic alaphelyzetben a sorparaméter-tábla (ld. LPT sorozat)
első COL0 bájtja a 47368-as címen van. Ha ekkor kiadjuk a
POKE 47368,255
parancsot, akkor a képernyő tetején egy fehér csík lesz látható. A sorparaméter-tábla mindig a 255-ös sorszámú szegmensen van, ez lesz tehát a szegmensszám. Az ofszetcímet megkaphatjuk, ha vesszük a cím 16384-es modulusát (osztás utáni maradékát), a MOD(47368,16384)-et. Ennek eredménye 14600, jöhet a
SPOKE 255,14600,255
parancs, az eredmény ugyanaz, mint fent. Van azonban egy igen lényeges különbség: ha valamilyen okból eltűnik a 2-es lapról a 255-ös szegmens, és mi kiadjuk a POKE 47368,255 parancsot, akkor egészen biztosak lehetünk abban, hogy rossz helyre ment a 255-ös érték. A POKE paranccsal egyébként is csínján kell bánni, mert igencsak katasztrófális helyzeteket idézhetünk elő a rendszerben... Ugyanez nem fordulhat elő a SPOKE-al! A ROM Basic ugyanis saját, belső memórialapozásával gondoskodik arról, hogy az érték garantáltan jó helyre kerüljön, megmentve a felhasználót ettől a feladattól.
A SPEEK (Segment PEEK) függvénnyel bájtot tudunk beolvasni
egy szegmens adott címéről, a forma:
érték=SPEEK(szegmensszám,ofszetcím)
A szegmensszámra, az ofszetcímre, az értékre ugyanaz vonatkozik, mint ahogy
azt fentebb megtudtuk.
Az előző példa folytatásaként olvassuk be a szín kódját, de a "látvány"
kedvéért lapozzuk le a 255-ös szegmenet a 2-es lapról, adjuk ki:
OUT 178,0
Most teljesen közömbös, hogy miért épen a nullás szegmenet rakjuk a helyébe. A lényeg az, hogy ha a
PRINT PEEK(47368)
parancsot végrehajtja a Basic, akkor 252-öt fog kiírni, ami biztosan rossz, hiszen az imént 255-öt küldtünk oda (csak éppen másik szegmensre). De a
PRINT SPEEK(255,14200)
után a helyes 255 jelenik meg a képernyőn. A példa egy kicsit erőltetett, hiszen mi magunk tüntettük el a szegmenet, de ugyanezt az EXOS is teljes joggal megtehette volna.
Ha valaki elsősorban Basic-ben írja programjait, akkor előbb-utóbb
gyorsítani szeretné őket, ekkor veti be a Zzzip Basic fordítót. Köztudott, hogy
a Zzzip ún. integer fordító, azaz a programban szereplő számok csak a -32768...+32767
tartományba eshetnek. Ha egy ilyen programba a minimál Basic POKE, PEEK parancsait
használjuk, akkor nagy valószínűséggel az őket követő címértékek láttán kiakad
a fordító. Ezt a problémát a SPOKE, SPEEK kiküszöböli.
A cikk közepe táján azzal büszkélkedtünk, hogy a két utasítást használva nincs
szükségünk memórialapozásra. Ez így is van, de ne feledkezzünk meg a 16KB-nál
nagyobb memóriatartományok kezeléséről sem! Tegyük fel, hogy megnyitottunk egy
grafikus lapot, amelynek mérete 20KB, azaz két videoszegmensen helyezkedik el.
Ha ezt a 20KB-os tartományt kezelni akarjuk, akkor a műveletek előtt mindig
el kell tudnunk dönteni, hogy az ofszetcím éppen melyik szegmensre vonatkozik.
Ha a közvetlen memóriakezelés vagy a SPOKE/SPEEK nyújtotta lehetőségek között
kell döntenünk, akkor ugyanúgy járhatunk csak el, mint általában: a feladat
pontos ismeretében, alapos mérlegelés után kell a megfelelő megoldást kiválasztanunk.
ZozoSoft kiegészítése:
Elegánsabb megoldás, ha nem találomra választunk nagyobb mennyiségű adat tárolására szegmenst, hanem az EXOS-tól igénylünk:
ALLOCATE 9
CODE GETSEGMENT=HEX$("F7,18,67,69,C9")
CODE FREESEGMENT=HEX$("4D,F7,19,C9")
LET WS=USR(GETSEGMENT,0)
WS-be kerül a kiutalt szegmens száma, melyet ettől kezdve szabadon felhasználhatunk adattárolásra. Természetesen így akár egymás után több szegmenst is igényelhetünk!
Ha WS értéke nagyobb mint 255, akkor hiba volt (ez lehet megosztott szegmens lefoglalásakor is), ekkor a felsőbájt (azaz az érték/256) a hibakód.
A programfutás befejezése előtt "illik" felszabadítani lefoglalt szegmenst (különben hamar elfogyhat a memória!):
CALL USR(FREESEGMENT,WS)
Ha valaki visszaretten a memóriakezelés eme módjáról, használhatja HSOFT ugyanezen elv szerint működő MEM nevű BASIC-bővítését, mely leveszi a vállunkról a közvetlen memóriakezelés terhét.
Enterpress 1991/3.
A
közvetlen lemezkezelés rejtelmei
Az LPT sorozat befejezése óta nem sok újdonságot olvashattak az igazán profi
ENTERPRISE programozók Most azonban ismét itt van egy olyan téma amelyben az
ENTERPRISE legmélyebb lelkivilágába próbáljuk elvezetni a bátrabb olvasókat.
Azt általában minden lemezegységgel rendelkező tudja, hogy a kontroller-kártya
agyát egy WD1770-es vagy újabb változatokban egy WD1772-es floppy disk kontroller
chip alkotja. De ezen IC közvetlen programozását már kevesen ismerik, ezért
most erről lesz szó.
A WD1770 egy 28 lábú DIP tokozású NMOS alapú integrált áramkör, amely az egy-
és kétoldalas lemezegységek meghajtására egyaránt alkalmas, de csak szimpla
és dupla sűrűségű felírásra képes. Tehát normál esetben maximum 800 Kbájtos
lemezeket képes kezelni. A WD1772 csak annyiban különbözik a 1770-estől, hogy
gyorsabb az író/olvasó fej léptetése. Ennyi bevezető után rá is térhetünk a
lényegre, vagyis a programozásra.
A koncrollerrel négy írható / olvasható porton keresztül lehet kommunikálni,
ezek sorban a következők:
Olvasásnál: | Írásnál: | |
10h | Állapot regiszter | Parancs regiszter |
11h | Track regiszter | Track regiszter |
12h | Szektor regiszter | Szektor regiszter |
13h | Adat regiszter | Adat regiszter |
Ezeken kívül van még egy port amely a kontroller-kártyához tartozik, a 18h port, ennek használatáról később lesz szó, ugyanis ez nem a WD1770-es közvetlen portja- A kiadható parancsok a kővetkezők:
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | -bit |
0 | 0 | 0 | 0 | h | V | r1 | r0 | - Fej alaphelyzetbe álirtása |
0 | 0 | 0 | 1 | h | V | r1 | r0 | - Fej pozícionálása |
0 | 0 | 1 | u | h | V | r1 | r0 | - Fej léptetése |
0 | 1 | 0 | u | h | V | r1 | r0 | - Fej léptetése befelé |
0 | 1 | 1 | u | h | V | r1 | r0 | - Fej léptetése kifelé |
1 | 0 | 0 | m | h | E | 0 | 0 | - Szektor olvasása |
1 | 0 | 1 | m | h | E | P | a | - Szektor írása |
1 | 1 | 0 | 0 | h | E | 0 | 0 | - Cím olvasása |
1 | 1 | 1 | 0 | h | E | 0 | 0 | - Track olvasása |
1 | 1 | 1 | 1 | h | E | P | 0 | - Track írása |
1 | 1 | 0 | 1 | I3 | I2 | I1 | I0 | - Parancs megszakítás |
A táblázatban használt betűjelzések jelentése:
r1 | r0 | WD170 | WD1772 |
0 | 0 | 6 ms | 2 ms |
0 | 1 | 12 ms | 3 ms |
1 | 0 | 20 ms | 5 ms |
1 | 1 | 30 ms | 6 ms |
Az állapotregiszter bitjeinek jelentése:
A lemezműveletek használata a következő: a megfelelő parancs kódját be kell írni a D parancsregiszterébe a 10h porton keresztül. Ezt csak akkor tehetjük meg, ha az állapotjelző bájt 0. bitje, vagyis a foglaltság jelző törölt állapotú. A művelet befejezése után a státuszbájt kiolvasásával ellenőrizhetjük, hogy a folyamat hibamentesen zajlott-e le vagy, hogy milyen hiba tőtrént. Most pedig következzen az egyes parancsok részletes leírása.
Fejmozgató parancsok
Ezen utasítások mindegyikénél a parancsbájt alsó két bitje adja meg a fejléptetés
sebességét, vagyis, hogy két léptető impulzus kiadása között mennyi legyen a
várakozási idő.
Az alaphelyzetbe állító parancsnak semmilyen más adatra nincs szüksége, hatására
az író/olvasó fej a 0-ás sávra áll be. A művelet befejeztével a track-regiszter
nullázódik.
Fej pozicionáló parancs kiadása előtt a Track regiszterbe az aktuális track
számát kell beírni, az adatregiszterbe pedig a beállítandó sáv számát. Az utasítás
befejeztével a fej a kívánt sávon fog állni és a track-regiszter is ezt az értéket
fogja tartalmazni.
A léptetés paranccsal egy pozícióval léptethetjük a fejet abba az irányba amelyet
utoljára használtunk. Az u-val jelzett bittől függően a WD a Track-regisztert
is beállítja.
A fej befelé léptetésével a nagyobb számú sávok felé, a kifelé léptetéssel a
0-ás sáv felé lép a fej. Itt szintén az u bit állapotától függ, hogy a Track-regisztert
is növeli / csökkenti vagy sem.
Szektorműveletek
Szektor írási és olvasási utasításoknál a parancskód kiadása előtt be kell állítani
a fejet a kívánt sávra, majd be kell írni a szektor-regiszterbe a megfelelő
szektor számát. Az E bit állapotától függően a parancs kiadása után vagy azonnal
megkezdődik a végrehajtás vagy egy 30ms-os késleltetés után. Ha nem találja
a megcélzott szektort, akkor szektor nem található hibával befejeződik a végrehajtás.
Ha az m bit beállított állapolt, akkor az írás / olvasás nem csak egy szektorra
vonatkozik, hanem egészen addig tart amíg a sávon található legnagyobb számú
szektor is sorra kerül.
Szektor olvasásakor az egyes bájtokat az adatregiszterből lehet kiolvasni. Azt,
hogy készen áll-e a bájt a kiolvasásra az állapotbájt 1-es bitjéből lehet megállapítani.
Ha ez a bit egyes akkor, kiolvasható az adat, kiolvasás után a bit törlődik,
és az is marad míg a következő bájt készen nem lesz. Ha egy adatbájt nem kerül
kiolvasásra a következő bájt megérkezéséig, akkor az állapotbájt 2-es bitje
beállított állapotúvá válik, ami az adatvesztést jelzi, de a beolvasás ekkor
sem szakad meg.
Szektor írásakor a parancs kiadása után az adatregiszterbe kell sorban beírni
az adatokat amit a lemezre akarunk írni. Az állapotbájt 1-es bitjének beállított
állapota jelzi, ha küldhetjük a következd adatot. Ha nem írjuk be a bájtot az
adatregiszterbe időben akkor beállított lesz az adatvesztés jelzőbit és a lemezre
0-ás bájt kerül kiírásra.
A cím olvasási parancs a szektor olvasáshoz hasonlóan működik, de itt nem lehet
megadni szektorszámot, hanem a legelső megtalált szektorazonosító blokkot lehet
beolvasni. Egy ilyen blokk 6 bájt hosszóságú, és a kővetkező adatokat tartalmazza:
1. bájt - Track száma (0-79)
2. bájt - lemezoldal száma (0-1)
3. bájt - Szektor száma. (0-255)
4. bájt - Szektor mérete. (0-3)
5. bájt - CRC 1
6. bájt - CRC 2
A szektorméretek az alábbiak lehetnek:
00 = 128 bájtos szektor
01 = 256 bájtos szektor
02 = 512 bájtos szektor
03 = 1024 bájtos szektor
IBM formátumú lemez mindig 512 bájtos szektorokat tartalmaz. Ez a funkció a
fejpozicionálás ellenőrzésére használható.
Track-műveletek
Ide két parancs tartozik, a track olvasás és a track írás ami nem más, mint
a formázás. A szektorműveletekhez hasonlóan itt is be kell pozícionálni a fejet
a megfelelő sávra mielőtt kiadjuk az utasítást.
Sáv olvasása szinte teljesen megegyezik a szektorolvasással, de itt nem kell
szektorszámot megadni. A betöltés az indexlyuk megtalálásával kezdődik, és egészen
addig tart amíg másodszorra elérkezik az indexlyukhoz, vagyis amíg a lemez egyszer
körbefordul. Ilyenkor minden betöltődik ami a lemezen van, tehát a szektorok
adatain kívül a szektorközti területeket (lásd formázásnál) is. A különböző
szinkronváltások miatt a Gap területen lévő bájtok hibásak is lehetnek, sőt
akár adatvesztés is bekövetkezhet, de az index címjelzés, az index mező, az
adat címjelzés, az adatmező és a CRC bájtok helyesek lesznek.
A sáv írása nem más mint a formattálás, vagyis fel kell írni a track-re a szektorazonosítókat,
az adatmező helyét és a szektorközti területeket.
A sáv felépítés: Gap I, Szektorok területe, Kitöltés
A szektorok felépítése: Gap II, Szektorfej, Gap III, Adatbező, Gap IV
Mint látható, egy szektor nem csak magából az adatterületből
áll, hanem a szektorazonosítókból, különböző jelzőbájtokból és kitöltő területekből
(Gap-ekből) is.
A Gap-eknek fontos feladatuk van, nem csak foglalják a helyet foglalják, hanem
időzítenek is. Egy szektor adatainak beolvasása után ugyanis szüksége van a
WD-nek egy bizonyos feléledési időre, mire a következő olvasást elkezdheti.
Formázáskor a szektorok felépítését annyiszor kell felírni a lemezre ahány szektorra
akarjuk formázni a lemezt. Egy sáv mérete névlegesen 6250 bájt dupla sűrűségű
felírás esetén, és 3125 bájt szimpla sűrűségnél, formázáskor azonban érdemes
még rátenni egy kicsit, vagyis megnövelni a legutolsó kitöltő területet a sebességváltozások
miatt, tehát dupla sűrűségnél 6500 bájtot, szimplánál 3250 bájtot kell kiküldeni
a WD-nek. A Gap~k ajánlott felépítése: (a Gap II kivételével mindegyiktől el
lehet térni, de csak az egyes bájtok számának növelésével.)
A Gap-ek felépítése |
|
-FM |
-MFM |
Gap I - 16 bájt - 0FFh |
32 bájt - 4Eh |
Gap II - 11 bájt - 0FFh |
22 bájt - 04Eh |
6 bájt 00 |
12 bájt 00 |
- 3 bájt 0F5h |
|
Gap II - 10 bájt - 0FFh |
24 bájt - 4Eh |
4 bájt - 00 |
8 bájt - 00 |
- 3 bájt 0F5h |
Az adatok felírását a sávra a szektoríráshoz hasonlóan kell elvégezni. Fizikailag az írás az indexlyuk elérésénél kezdődik, és egy teljes lemezfordulatig tart. A szektorírástól eltérően itt nem minden bájt íródik fel egy az egyben a lemezre, hanem vannak speciális bájtok amelyeket a WD eltérően kezel. FM felírásnál (szimpla sűrűség) a F08h és 0FEh közötti bájtok a CRC ellenőrzés inicializálására valók, ugyanezt MFM felírásnál (dupla sűrűség) a 0F5h bájt kiküldésével érhetjük el. Mindkét felírási módnál 0F7h hatására két CRC bájt íródik a lemezre, 0FEh a szektorfej jelzése és 0FBh az adatmező jelzése. A szektorfej és az adatmező után is fel kell itatni a lemezre a két CRC bájtot, tehát egy 0F7h bájtot kell elküldeni a WD-nek. A fentiekből következik, hogy a Gap-ekben, a szektorfejben és az adatmezőben nem használhatók a 0F5h és 0FEh közti értékek.
Megszakítás
Ezzel a paranccsal különböző megszakításokat lehet kérni a WD-től, az I0-I3
bitek beállításától függően, azonban ENTERPRISE-on ezt nem tudjuk kihasználni,
mert a megszakítási láncban nem szerepel. Ezért csak egy beállítás mellett van
értelme a használatának, az I0-I3 biteket nullára állítva (0d0h) a folyamatban
lévő parancsot tudjuk megszakítani.
Nem esett szó még egy pontról ami a kontroller-kártyához tartozik, de nem a WD közvetlen portja. Ez a 18h port amelyen a használni kívánt meghajtót tudjuk kiválasztani. Ezt az alsó négy bit valamelyikének beállításával tehetjük meg. Értelemszerűen a 0-ás bit az A meghajtót, az 1-es bit a B meghajtót stb. jelenti. A portya irt érték 4-es bitjével pedig a meghajtó 0-ás és 1-es oldala között tudunk szelektálni. Ha például 12h értéket küldünk a 18h ponca, akkor a következő parancs a B jelű lemezegység 1-es oldalára fog vonatkozni.
További információk
A szektorfej felépítése |
Az adatterület felépítése |
0FEh (Szektorfej jelzése) |
0FBh (Adatterület jelzése) |
Sáv száma (0-0F4h) |
Szektorméretnek megfelelő számú adatbájt |
Lemezoldal száma (0 vagy 1) |
0F7h (CRC felírása) |
Szektor száma (1-0F4h) |
|
Szektor mérete (0,1,2,3) |
|
0F7h (CRC felítása) |
Egy tanács
Ha a közvetlen lemezkezeléssel kísérletezünk, akkor soha ne olyan lemezen próbáljuk
ki, amelyen fontos adataink vagy programjaink vannak, mert könnyen tönkremehetnek
egy esetleges programhiba miatt.
DEVIL - Enterpress 1992/1-1992/2
Az Enterprise DOS lemezek felépítése
A mágneslemez felépítése
A lemez lehet egy-, vagy kétoldalas. A kétoldalas meghajtóval mindkét formátumot tudjuk kezelni. A lemez homlokfelületén a koncentrikus körök - SÁVOK - hordozzák a mágneses információkat. Számuk 40, vagy - duplasűrű forma esetén - 80. A duplasűrű meghajtóval kezelhetünk szimplasűrű lemezt is, de ekkor csak a páros sávokat használjuk. (A sávok számát - korlátozott mértékben - növelhetjük is.) A sávokon 512 byte-os szektorok helyezkednek el. Minden szektor önálló szektor-azonosítóval van ellátva. A sávonkénti szektorszám (512 byte-os szektorokat feltételezve) 8 vagy 9, de 11-ig (ZOZOSOFT újításával 13-ig) lehetséges a számukat bővíteni.
A szektorazonosító felépítése:
byte 0. 0-89 TRACK megadott értékek az általában használtak, 1. 0-1 SIDE 0 és 255 között bármi lehetséges, 2. 1-13 SECTOR másolásvédett lemezeknél 3. 0-3 BYTE/SECTOR (0=128, 1=256, 2=512, 3=1024) 4-5 0-FFFFH CRC
A DOS lemezek felépítése
BOOT szektor
A DOS lemezek 0. oldal, 0. sáv, 1. szektorát beolvasva megkapjuk a lemez BOOT szektorát. Az itt található adatok alapján meghatározható a lemez fizikai és logikai felépítése. Az alábbi táblázat lemezekre készült, de a csillaggal jelölt változók RAMDISK esetében is használhatók, a '-'-al jelölteket nem veszi figyelembe az EXDOS, a '!'-lel jelölteknél a megadott értékeken kívül eső érték esetén valamilyen szokásos értékre konvertál, esetleg kijelenti, hogy nem DOS lemez. A '@' jelölésűeket pedig az EPDOS hagyja figyelmen kívül. Az 'X' jelzi azt, hogy az adott értékre nincs ellenőrzés, ilyenkor nekünk kell gondoskodni arról, hogy értelmes adatok legyenek. (Például ne legyen több a BOOT szektorok száma a lemez szektorainak számánál.) A megadott értékek az EXDOS alatt helyesen kezeltek, zárójelben a használt érték. A ^ jellel jelölteket az MSDOS 6.0 sem kezeli, pedig a MICROSOFT találta ki a DOS formátumot.
00-02 | - |
EBH. FEH, 90H IBM ( Ugrás a betöltő kódra) | ||||
03-10 | - |
"EXDOS 1.0" rendszer (formázó software) | ||||
11-12 | * |
! |
^ |
#200 byte / szektor | ||
13 | * |
! |
1-2 szektor / cluster | |||
14-15 | * |
X |
@ |
^ |
1-FFFFH (1) szektor / boot | |
16 | * |
@ |
^ |
1-7 (2) FAT példányok száma | ||
17-18 | * |
X |
1-FFFFH (40H-70H) ROOT_DIR (főkönyvár MAX_FILE) | |||
19-20 | * |
Formától függő szektor / disk | ||||
21 | - |
* |
! |
F8H-FFH FORMA_TYPE | ||
22-23 | * |
X |
1-FFFFH szektor / FAT | |||
24-25 | 8-10-11-13-18-22 szektor / track (EXDOS verziótól függ) | |||||
26-27 | ! |
1-2 SIDE (oldalszám) | ||||
28-29 | * |
X |
@ |
^ |
0-FFFFH (0) fenntartott | |
Innentől csak EXDOS (vagy VT-DOS) lemezeken: | ||||||
30 | - |
^ |
C9H RET, az MSX-DOS BOOT program belépési pontja | |||
31-63 | - |
^ |
0 nullázás | |||
64-69 | * |
^ |
"VOL_ID" azonosító string | |||
70 | * |
^ |
0 UNDEL jelző-byte | |||
71-74 | * |
^ |
X1, X2, X3, X4 32 bites lemezazonosító | |||
75-99 | - |
^ |
0 nullázás | |||
100-511 | - |
^ |
E5H üres terület |
A típus-byte RAMDISK esetében 2AH, lemezeknél F8H-FFH, ahol az alsó 3 bitnek formai jelentése van.
0. bit =1 oldalak száma 2 1. bit =1 sávonként 8 szektor 2. bit =1 szimplasűrű sávkiosztás 3-7. bit =1 beállított
3. bit = 0 - 3.5", HD lemezFFH - DS/SD/8 (320K)
FEH - SS/SD/8 (160K)
FDH - DS/SD/9 (360K)
FCH - SS/SD/9 (180K)
FBH - DS/DD/8 (640K)
FAH - SS/DD/8 (320K)
F9H - DS/DD/9 (720K)
F8H - SS/DD/9 (360K)
F0H - DS/DD/18 (1440K)Az EXDOS leellenőrzi, hogy a típus-byte F8H (F0H)-FFH közé esik-e, de ténylegesen nem ez alapján kezeli a lemezt, hanem a BOOT szektor adatai alapján. FAT-1 A file-ok raktározására az elemi adatblokkok (CLUSTER), illetve ezeknek a láncolata hivatott. A blokkok könyvelése a FAT-területen történik. A mutatók mindegyike 12 bites szám, melyek sorban helyezkednek el. Pl. az 5. cluster foglaltságát 5*12 bit-től kezdve olvashatjuk. Az értékek jelentése:
000H - szabad cluster
FFFH - file vége
FFEH - nem használható cluster
FF7H - hibás cluster
egyéb - annak a clusternek a száma, ahol a file folytatódik.A rendszer 0-ás és 1-es clustert nem használ, ezért helyükön #Tp, #FF, #FF byte-ok találhatók. (Tp = típus-byte) FAT-2 (vagy az utolsó FAT példány) A FAT-1 minden írási művelet esetén átmásolódik a FAT2 területre. Törlés esetén a cluster-ek felszabadítása csak a FAT-1 területen történik. UNDEL esetén a FAT-2 alapján helyreállítható az eredeti állapot. Ha csak 1 FAT van akkor nincs lehetőség az UNDEL-re. Ha 2-nél több FAT példányt használunk, akkor az utolsó kivételével mind a FAT-1 másolata, és ha a FAT 1 fizikailag megsérül, akkor amíg az EXDOS legalább egy jó példányt talál, addig helyesen (hibajelzés nélkül) kezeli a lemezt.
ROOT DIR A főkönyvtár a file-ok könyvelésére szolgáló, kötött méretű terület. Minden file-hoz 32 byte-os leíró tartozik. Egyes byte-ok jelentése:
00 file név első betűje, E5H ha törölt a file, 0 ha szabad bejegyzés 01-07 file név 08-10 kiterjesztés 11 attribútum 12 törlés után a név első betűje, egyébként 0 13-21 nulla (nem használt) 22-23 idő 24-25 dátum 26-17 kezdő cluster 28-31 méret
attribútum 0. bit = 1 READ ONLY 1. bit = 1 HIDDEN 2. bit = 1 SYSTEM 3. bit = 1 VOLUME 4. bit = 1 DIRECTORY 5. bit = 1 ARCHIVE 6., 7. bit 0 TIME, DATE byte:
File elhelyezési tábla (File Allocation Table, FAT)
A FAT 12 bites bejegyzéseket tartalmaz, a lemez minden alapegységéhez egyet. Az első két bejegyzés a 0. és az 1. alapegységhez tartozik, amelyek nem léteznek, így az első alapegységhez tartozó FAT bejegyzés a FAT 4. byte-ján kezdődik. A FAT első 3 byte-ja a következő :
0. byte : FATID byte, mindig F8h...FFh
1. byte : mindig FFh
2. byte : mindig FFh
A FATID byte a lemezformátum meghatározására szolgál, ha nincs UPB a boot-szektorban, egyébként nem használatos.
Minden alapegységhez tartozó bejegyzés nulla, ha az alapegység szabad, egyébként az alapegység része egy file-nak, és a bejegyzés értéke a file következő alapegységének a számát adja meg. A file utolsó alapegységét a FF8h...FFFh értékek valamelyike jelzi. Ezáltal a file-t alkotó alapegységek láncba fűzötten jelennek meg a FAT-ban.
A FF0h...FF7h értékek a fenntartott alapegységeket jelölik, ha azok nem alkotják egy lánc elemét sem: a FF7h jelzi a hibás alapegységeket, amelyeket nem szabad használni.
Egy lemez a FAT-ot akárhány példányban tartalmazhatja. A másodpéldányokat akkor használják, ha az első lemezhiba miatt olvashatatlanná válik. Rendszerint az összes példány egyforma, de létezik egy kivétel ez alól (a file-visszaállítás érdekében).
Rendszerváltozók
VERIFY Automatikus ellenőrzés írás után (0=be, FFh=ki) DEF_UNIT Default Unit (meghajtó megadásának hiányában használt egység) száma : 1...26 BOOT_DRV Nem használt. STEP_RATE Léptetés az UNITH számára (0=6ms, 1=12ms, 2=20ms, 3=30ms) DSK_CHK 0 esetén engedélyezve a teljes diszk-változás ellenőrzés a már nyitott file-okra AB_ERR ABORT hibát eredményező diszk-hibakód BCH_DIS Ha nem 0, a DOS "elhiszi", hogy a diszk nem változott.
DISKIO hívások
A használt rövidítések:
TRC: transzfercím (IX-regiszter)
MEGH: meghajtó maszk (B-regiszter 0.bit=A, 1.bit=B, 2.bit=C, 3.bit=D)
OLD: oldalszám (SIDE) (0-1) (C-regiszter 0. bitje)
SÁV: sávszám (TRACK) (0-254) (D-regiszter) (a 255 az aktuális sáv)
SZEK: szektorszám (SECTOR) (1-13) (E-regiszter)
SZEKN: szektorok száma (1-13) (L-regiszter)
ST: státus (H-regiszter)
bit 0-1 = fejléptető sebesség,
bit 2 = előkompenzálás engedélyezése,
bit 3 = duplasűrű meghajtó szimplasűrű lemezt kezel,
bit 5 = felírási mód (0=MFM, 1=FM)A hívás általános tudnivalói:
parancsok bit 0 = BA NOT READY (1-6, 8) 1 = B9 VERIFY ERROR (3) 2 = B8 LOST DATA (1-6) 3 = D8 DATA ERROR (1-6) 4 = B7 RECORD NOT FOUND (1-3, 6) 5 = fenntartva 6 = B6 WRITE PROTECTED DISK (2, 4) 7 = BD kb. hibás diszkkezelő kódszám (9-255) nincs megadva meghajtó (1-7)
00. Diszk reset
B=MEGH (A következő pozicionálás nem relatívan fog történni), egyszerre több meghajtó is megadható.01. Szektorok olvasása
B=MEGH
C=OLD
D=SÁV
E=SZEK
H=ST
L=SZEKN L=beolvasott szektorok száma
IX=TRC02. Szektorok írása
B=MEGH
C=OLD
D=SÁV
E=SZEK
H=ST
L=SZEKN L=kiírt szektorok száma
IX=TRC03. Szektorok ellenőrzése
B=MEGH
C=OLD
D=SÁV
E=SZEK
H=ST
L=SZEKN L=ellenőrzött szektorok száma
IX=TRC04. A teljes sáv írása
B=MEGH L=1
C=OLD
D=SÁV
H=ST
IX=TRC05. A teljes sáv beolvasása
B=MEGH L=1
C=OLD
D=SÁV
H=ST
IX=TRC06. A sávon található szektor azonosítók beolvasása
B=MEGH
C=OLD
D=SÁV
H=ST L=beolvasott azonosítók száma
L=azonosítók száma
IX=TRC (L*6 bájt került beolvasásra)07. ?
B=MEGH08. Meghajtó vizsgálat
B=MEGH
H=ST Ha az L=FF akkor a meghajtó duplasűrű
Ha a B=0, akkor eldönti, hogy egy meghajtós-e a rendszer: A=0 ha igen.
FISH hívások
A használt rövidítések:
STR: eszköz:\ösvény\fájlnév .kiterjesztés
UV: útvonal (ösvény)
MEGH: meghajtó száma (1 = A, 2 = B, 3 = C, stb, 0 = aktuális)
FMEGH: fizikai meghajtó száma
KFCB: kereső fájl kontrol blokk
MFCB: meghatározott fájl kontrol blokk
TRC: transzfercím (felhasználói puffercím)
SIZE: bájtok száma (fájl vagy blokk méret)
SZEK: logikai szektorszám (kezdő szektorszám)
SZEKN: szektorok száma (mozgatandó szektorok)A hívás általános tudnivalói:
01. Útvonal és KFCB készítés fájlnévből
DE = KFCB C = STR következő karaktere
HL = STR DE = STR folytatása
HL = UV (az STR-ben kialakítva)
IX = KFCB (meghajtó és fájlnév kitöltve)Eredmények :
A = állapotkód
B = visszatérési jelzőbitek
C = záró karakter
DE -> záró karakter
HL = változatlanEz a funkció megkönnyíti a parancssorok elemzését, mivel közvetlenül a FISH-nek átadható útvonalnév-stringet és használatlan FCB-t készít. Tisztán karakterlánc manipulációs funkció, egyáltalán nem fordul a diszk-hez. Fő működése az, hogy kialakít egy érvényes útvonal-stringet abból a karakterláncból, amelyre a HL mutat, úgy, hogy az átadható egy keresési vagy létrehozási FISH funkcióhívásnak.
Ha az utvonalnév-string magában foglal egy file-nevet, akkor azt át lehet másolni a DE által kijelölt FCB-be, amit aztán át lehet adni a FISH-nek mint használatlan FCB-t. A DE által kijelölt FCB-nek érvényes keresési attributumokkal es meghajtószámmal kell rendelkeznie, az FCB további részei kitöltetlenek is lehetnek.
A keresési attributum-byte kötetnév bitje dönti el, hogy "meghajtó/útvonalnév/filenév", vagy "meghajtó/kötetnév" karakterláncot kell-e elemezni.
Ha a kötetnév bit "0" ,akkor a karakterlánc szintaxisa egy opcionális meghajtónév és az ezt követő directory-név sorozat, melynek elemeit "\", "!" vagy " ' " karakterek választják el egymástól. Ha egy elem nem "\" karakterrel van lezárva, akkor azt az utolsó elemzendő egységnek tekinti a FISH. Ezt az utolsó elemet vagy bemásolja az FCB-be, ha a C regiszter "0" volt, vagy belekerül az útvonal-stringbe, ha C regiszter "1" volt. A file-név, ha bemásolódik az FCB-be, végig nagybetűs lesz, szóközökkel kiegeszítve és minden "*" karakter a megfelelő számú "?"-lel kifejtve.
Ha a kötetnév bit "1", akkor a karakterlánc ugyanazt az opcionális meghajtónevet tartalmazza, de utána egy kötetnév következik, amely átmásolódik az FCB-be. A kötetnév bármilyen karaktert tartalmazhat az első "/" karakterig. Minden más file-név végkarakter (a szóköz) is megengedett a kötetnévben, és a kötetnév nem csak nagybetűket tartalmazhat mint a file-név.
A visszaadott útvonalnév-string csak a meghajtónevet foglalja magában.
Ha a karakterlánc meghajtónévvel kezdődik, akkor ez a meghajtószám beíródik az FCB megfelelő byte-jára. Ha nincs meghajtónév a karakterláncban, akkor az FCB-ben levő meghajtószám nem változik, csak ha 0. Ez utóbbi esetben a DEF_UNIT rendszerváltozó értékét veszi fel.
Visszatéréskor a HL regiszterpár tartalma nem változik, s így az érvényes útvonalnév-string kezdőpontjára mutat, amely készen áll arra, hogy a FISH-nek átadják. A string magában foglalja a meghajtót (ha van) és directory elemeket, a korábban leírtak szerint. A string egy null-karakterrel végződik a megfelelő helyen, de ettől eltekintve változatlan marad.
A DE regiszterpár az eredeti karakterláncban az első fel nem dolgozott karakterre fog mutatni, amely lehet a karakterlánc vége is, ha az egész string feldolgozásra került. A HL által kijelölt karakterlánc végére kerülő null-karakter felülírhatja a DE által megcímzett pozíción lévő eredeti karaktert, ezért ezt a C regiszterben külön visszaadja a FISH. Ne tekintsük ezt a karaktert érvényesnek a stringben, de az útvonalnév-string használata után visszaírhatjuk.
A visszatérési jelzőbitek, amelyeket a B regiszterben kapunk vissza, bizonyos, potenciálisan hasznos tényeket közölnek az elemzési műveletről az alábbiak szerint:B 0. bit = 1 ha a meghajtónéven kívül más kielemzett karakterek is vannak
B 1. bit = 1 ha volt specifikált útvonal
B 2. bit = 1 ha van specifikált meghajtónév
B 3. bit = 1 ha az utolsó elem file-név
B 4. bit = 1 ha az utolsó elem kiterjesztés
B 5. bit = 1 ha az utolsó elem többértelmű ('?' vagy '*')
B 6. bit = 1 ha az utolsó elem speciális ('.' vagy '..')
B 7. bit 7 1 ha az utolsó elem '..', csak ha 6. bit is 1
02. Aktuális katalógus megadás
HL = UV HL = UVEz a funkció megváltoztatja az aktuális directory-t az adott meghajtón. Az útvonalnév-string megadja a meghajtót (ha nem, akkor az implicit meghajtót használjuk) és egy al-directory listát. Ha "." vagy ".." elemek találhatók benne akkor ezeket a FISH funkció megfelelően kifejti. Ha az útvonalnév-string "\", "!" vagy " ' " karakterrel kezdődik, akkor a régi aktuális útvonal figyelmen kívül marad, egyébként pedig az új útvonalnév hozzáadódik az aktuális útvonalhoz. Ha az útvonalon bármelyik directory nem létezik, akkor a FISH ".NODIR" hibát jelez, és az aktuális útvonal nem változik.
Az új aktuális directory-string azonos azzal a karakterlánccal, amelyet egy "aktuális directory beolvasása" funkcióhívás adna vissza és az ezen funkció leírásában olvasható megjegyzések ide is vonatkoznak .03. Aktuális katalógus lekérés
B = MEGH HL = UV (a FISH területen)Ez a funkció visszaad egy pointert, amely az aktuális útvonalnév-stringre mutat az adott meghajtón a karakterláncnak sem az elején, sem a végén nincsenek "\" karakterek, és 00h-val végződik. Ha az aktuális directory azonos a kiindulási directory-val, akkor a visszaadott karakterlánc null-string.
04. Első bejegyzés keresése
BC = MFCB BC = MFCB
DE = KFCB DE,IX = KFCB
HL = UV HL = UV (már a FISH területen)Az adott directory-ban olyan belépési pontot keres, amelyben a név meg-egyezik a DE által kijelölt FCB-ben levővel. Az FCB-ben lévő file-név többértelmű is lehet, mely esetben az első egyező nevet tartalmazó belépési pontot találja meg. Ha nem talál egyező nevet, akkor ".NOFIL" hibával tér vissza. A HL-ben kijelölt "teljes útvonal-string" nem érvényes, ha az indulásnál a DE "meghatározott FCB"-re mutat.
Ha a keresési FCB-ben az attributum-byte kötetnév bitje "1", akkor csak a kötetnév belépési pontot adja vissza a FISH-funkció és ezt mindig visszaadja (ha van), tekintet nélkül az FCB-ben lévő útvonalnévre, vagy file-névre. Ha a kötetnév bit "0", akkor a kötetcímke belépési pontot sohasem adja vissza, és másféle egyeneseket figyel. Ebben az esetben a hívónak kell vizsgálnia a "rendszer file", a "rejtett file" és "al-directory" biteket az attributum byte-ban, ha korlátozni akarja a keresést.
Ha a DE meghatározott FCB-re mutat, akkor annak egy meghatározott aldirectory-nak kell lennie (a directory-bejegyzésnél az attributum byte ellenőrzésre kerül), a meghatározott FCB-név mezőjét pedig előzetesen felül kellett írni az ebben az al-directory-ban keresendő új file-névvel.
Ha a FISH funkció talált egy megfelelő directory bejegyzést, akkor egy új meghatározott FCB-t hoz létre a BC által kijelölt címen. Ez egy FEh byte-tal fog kezdődni, amely után következő 7 byte a keresési FCB-ből másolódik át (ebben benne van a keresési attributum byte és a meghajtó), majd a directory bejegyzés 32 byte-ja. Az új FCB utolsó 8 byte-ja nem töltődik ki.
Jegyezzük meg, hogy az új FCB 6. byte-ja (az attributum byte) a keresési FCB megfelelő byte-jával lesz azonos, nem pedig a meghatározott directory- bejegyzés attributumával, amely a file-név utáni byte-on lesz.05. Következő bejegyzés keresés
BC = MFCB BC = MFCB (kitöltve)
DE = KFCB DE, IX = KFCB
HL = UV (FISH területen)Egy "első keresése" funkcióhívás után ezt a funkciót ismétlődően sokszor meg lehet hívni a további egyező nevek meghatározása céljából, ha a név többértelmű volt. A BC-ben megadott cím különbözhet az előző keresésben használttól, ha megmarad azokban az esetekben, mint az "első keresése" funkciónál.
A keresési FCB fenntartott része tartalmazza azokat az információkat, amelyekre a FISH-nek a keresés folytatásához szüksége van, így nem szabad módosítani az "első keresése" és a jelen funkció bármely hívása között. Szükség esetén elmentés céljából át lehet másolni, de ez általában elkerülhető.06. Fájl létrehozás
BC = MFCB BC = MFCB
DE = KFCB DE, IX = KFCB
HL = UV HL = UV (FISH területen)Ez a funkció nagyon hasonlít az "első keresése" funkcióhoz, kivéve, hogy többértelmű file-név nincs megengedve. Ha egyező névvel directory bejegyzést talál, akkor azt - ha lehetséges - kitörli és a hozzá allokált területet felszabadítja. Ha a bejegyzés nem törölhető, akkor a következők szerint egy megfelelő hibajelzéssel tér vissza:
".DIRX" - a bejegyzés egy directory. A directory-kat explicit módon kell törölni.
".SYSX" - a bejegyzés egy rendszer-file. Ezeket explicit módon kell törölni.
".FILRO" - a bejegyzés csak olvasható file. Ezeket nem lehet törölni ,csak ha előzetesen megváltoztatjuk a jellemzőjüket .Ha nem talál egyező névvel bejegyzést, akkor a directory-ban az első üres bejegyzést veszi használatba. Ha a directory tele van, akkor kibővíti egy alapegységgel (kivéve, ha a kiindulási directory-ban vagyunk, amikor ".DRFUL" hibát ad vissza, vagy ha nincs szabad alapegység a lemezen, amikor ".DKFUL" hibát jelez ).
Ha a "file-létrehozás" funkció talál egy megfelelő directory-bejegyzést, akkor beleírja a file-nevet az FCB-ből (".IFNM" hibával tér vissza, ha a file-név illegális), kitölti az attributum byte-ot úgy, hogy csak az "archiválás" bit "1", beírja a "0" file-méretet, valamint az aktuális dátumot és időpontot, amelyet a FISH rendszer-órája tart nyilván.
A BC-ben megadott címen egy erre az új bejegyzésre vonatkozó meghatározott FCB jön létre - pontosan olyan, amilyet az "első keresése" funkció ad vissza.
Az új file nem nyitódik meg automatikusan, egy külön "file-megnyitás" funkcióhívásra van szükség, hogy írni vagy olvasni lehessen. Ha azt akarjuk, hogy a file rendszer-file, vagy rejtett, vagy csak olvasható legyen, ezt a létrehozás után egy "file-attributumok változtatása" funkcióhívással érhetjük el.
Ha a használatlan FCB-ben a keresési attributum byte kötetnév bitje "1", akkor ez a funkció a lemez kötetnevét fogja létrehozni, vagy megváltoztatni. Ez esetben a kötetnevet keresi, s ha megtalálja kicseréli az FCB-ben levő névre. Ha nincs kötetnév-bejegyzés, akkor a kiindulási directory első üres bejegyzésén létrehozza a kötetnevet.
A funkcióból való visszatéréskor a DE által kijelölt FCB keresési FCB lesz. Ez a BC-ben megcímzett meghatározott FCB-vel együtt ugyanúgy használható, mintha az "első keresése" funkció adta volna vissza. Ez gyakran hasznos, ha megkíséreltünk egy létrehozást, és ".DIRX" hibajelzést kaptunk, tehát a név egy directory neve volt. A program tovább mehet, és létrehozhatja a file-t ebben a directory-ban. A BC és DE regiszterpárok tartalma megmarad az "első keresése" funkciónál ismertetett feltételek mellett.07. Katalógus létrehozás
BC = MFCB BC = MFCB
DE = KFCB DE, IX = KFCB
HL = UV HL = UV (FISH területen)Ez a funkció nagyon hasonló a "file-létrehozása" funkcióhoz kivéve, hogy nem file számára készít directory bejegyzést, hanem egy al-directory számára.
Megvizsgálja, hogy van-e az adott névvel directory bejegyzés, de ha talál egy ilyen file-t nem törli ki, még ha törölhető is lenne, hanem ".FILEX" hibajelzéssel visszatér.
Az új al-directory egy alapegységnyi diszk-területet foglal el és üres lesz, eltekintve a "." és ".." jelzésű két bejegyzéstől, amelyek a directory-ra magára, ill. a "szülő" directory-ra mutatnak. E két al-directory jellemzője "rejtett" lesz, így normál directory-listázáskor nem jelennek meg.08. Fájl vagy katalógus törlés
DE = MFCB IX = MFCB
HL = KFCBA meghatározott FCB-hez tartozó directory-bejegyzés törlődik, kivéve, ha csak olvasható file (".FILOR" hibajelzés), vagy nem üres al-directory (".DIRNE" hibajelzés). A "." és ".." al-directory-kat nem lehet törölni (".DOT" hiba-jelzés). Ha nincs hiba, akkor minden, a file-hoz vagy a directory-hoz rendelt lemezterület felszabadul. Ha a lemeznek van érvényes kötetazonosítója akkor a "piszkos diszk" jelző "1"-be áll, és a FAT utolsó példányában az alapegységek nem szabadulnak fel. Ez lehetővé teszi a file-ok visszaállítását az UNDEL program segítségével.
09. Fájl vagy katalógus átnevezés
BC = MFCB (új névvel)
DE = MFCB IX = MFCB
HL = KFCBA meghatározott directory-bejegyzés neve megváltozik a BC által megcímzett FCB-ben levő névre. Ez az új név többértelmű is lehet, ahol "?" fordul elő benne, azon a pozíción megmarad az eredeti karakter. Visszatéréskor a meghatározott FCB-ben az új név szerepel, a "?"-ek megfelelően helyettesítve.
Ellenőrzés történik, hogy ne keletkezhessen duplikált, vagy érvénytelen file-név; ha a funkcióhívás végrehajtása erre vezetne, akkor ".DUPF", ill. ".IFNM" hibajelzést ad vissza. A "." és ".." al-directory-k nem nevezhetők át, ennek megkísérlése ".DOT" hibajelzéshez vezet. A használatlan FCB-ben, a meghatározott és a keresési FCB-ben a meghajtónak azonosnak kell lennie, ha nem így van, ".IDRV" hibajelzés történik.
Ha olyan al-directory nevét változtatjuk meg, amely az aktuális directory-útvonalnak eleme, akkor az aktuális directory-útvonal a következő hozzáféréskor törlődik, mivel a FISH nem tudja relokálni a directory-útvonalat.10. Fájl vagy katalógus áthelyezés
BC = UV (új útvonal)
DE = MFCB IX = MFCB
HL = KFCBA meghatározott directory-bejegyzést kiveszi abból a directory-ból, ahol jelenleg van, és áthelyezi abba a directory-ba, amelyet a BC-ben megcímzett útvonalnév-string specifikál. ".IATTR" hibajelzés történik, ha a bejegyzés kötetnév. A funkció ellenőrzést végez, hogy ne keletkezzék duplikált filenév. Ha az új útvonalnévben meghajtó is szerepel, akkor ez meg kell, hogy egyezzen annak a meghajtónak a számával, ahol a directory-bejegyzés található, különben ".IDRV" hibajelzés történik.
Ha al-directory áthelyezéséről van szó, akkor további ellenőrzéseket végez a funkció, hogy nem a "." vagy ".." bejegyzéseket akarjuk áthelyezni és, hogy a directory-t nem valamelyik saját "leszármazottjába" akarjuk áthelyezni. Ez ".DIRE" hibajelzést eredményez, mivel hurkot hozna létre. Egy al-directory sikeres áthelyezése után a ".." bejegyzés aktualizálódik, az új "szülő" directory-ra.11. Attribútum és idő változtatás
DE = MFCB (módosított attribútum / idő / dátum)
HL = KFCB IX = MFCBEz a funkció kicseréli a meghatározott directory-bejegyzés attributum byte-ját, továbbá a dátum és időadatát a meghatározott FCB-ben szereplő adatokra. A directory-bejegyzés többi mezőjét változatlanul hagyja. Az attributum byte-ot ellenőrzi, hogy a változtatás megengedett-e, és ha nem akkor sem a dátumot és az időpontot, sem a jellemzőket nem változtatja meg, hanem ".IATTR" hibajelzéssel tér vissza. Az új dátumot és időpontot nem ellenőrzi.
Jegyezzük meg, hogy az új jellemzők a meghatározott FCB directory-bejegyzés példányában vannak definiálva, és nem a keresési attributum byte-ban. Az új datumok és időpontok a meghatározott FCB-ben a normál pozíción kell lenniük, ami nem azonos azzal a pozícióval, amelyet megnyitás után foglalnak el az FCB-ben.
12. Fájl megnyitás
DE = MFCB DE, IX = MFCB
HL = KFCBA meghatározott directory-bejegyzéshez tartozó file-t megnyitja, így az készen áll írásra vagy olvasásra. A bejegyzés nem lehet al-directory vagy kötetnév, és ha "csak olvasható", akkor írni nem lehet bele. A file mérete, a dátum, az időpont és a meghajtó aktuális kötetazonosítója bemásolódik az FCB-be, a file-mutató nullázódik. Az FCB azonnal használható a file elejétől induló szekvenciális írásra vagy olvasásra.
Jegyezzük meg, hogy a file-méret, a dátum és az időpont a megnyitott FCB-ben nem ugyan azon a helyen van, s nem is ugyan abban a sorrendben, mint a meghatározott FCB-ben volt a megnyitás előtt.13. Fájl lezárás
DE = MFCB DE, IX = MFCB
HL = KFCBLezárja az FCB-hez tartozó file-t. Azokat a file-okat, amelyeket csak olvastunk, nem szükséges lezárni; ha mégis lezárjuk a diszk-directory nem változik. Ha irtunk a file-ba, akkor a directory-bejegyzést megfelelően aktualizálja az új dátum-, idő-, méret- és helyfoglalási információkkal és az archiválási bitet "1"-be állítja.
Jegyezzük meg, hogy ha az FCB-ben a file-név megváltozik, akkor a lezárás nem történik meg helyesen. Az attributum byte sem változhat meg a directoryban; ezt csak az "attributumok változtatása" funkcióhívás teheti meg.
Az FCB a file lezárása után is használható a file-hoz való hozzáférésre, így a file-lezárás funkció arra is alkalmas, hogy hosszabb file-írás közben időnként a file változásait teljes egészében rögzítsük a lemezen biztonsági okokból. Egy FCB-t csak akkor szabad lezárni, ha előzőleg sikeresen megnyitottuk. AFISH-nek nincs módja ezt ellenőrizni; ha megkíséreljük, a hatása nem definiált és katasztrofális lehet.14. Pufferek törlése (Meghajtó adatterület lekérdezésre is használható)
B=MEGH B=0
(Ha B = 255, akkor minden puffert töröl)
C = 0 csak puffertörlés
HL = MEGH PTR (HL) = MEGH. puffer szegm.
(HL+1) = cím az 1. lapon
C = 255 pufferek törlése és érvénytelenítése
DE = MEGH terület az 1. lapon
HL = DE+9Ez a funkció kitörli az összes piszkos szektorpuffert az adott meghajtóra (vagy mindegyikre, ha B=FFh). A nyitott file-ok nem záródnak le (mivel a FISH nem tartja nyilván őket). Mindig 0 állapotkódot ad vissza, kivéve, ha a meghajtószám érvénytelen, vagy ha megnyomták a STOP billentyűt.
Ha a C regiszter 0 volt, akkor a "piszkos pufferek" törlődnek, de a bennük maradó adatok nem kapnak "érvénytelen" jelzést. Ha a C regiszter tartalma FFh, akkor a pufferek törlése mellett az adatok is érvénytelenek lesznek, így többé nem használhatók fel. Ebben az esetben is mindegyik meghajtó olyan jelzést kap, hogy a benne levő lemezt ellenőrizni kell.
Ezt a lehetőséget olyan külső programok alkalmazzák, mint a FORMAT vagy a DISKCOPY, amelyek közvetlenül "összemaszatolják" a diszket a DISKIO használatával, így biztosítva, hogy a FISH felismerje a módosított lemezt.15. Szekvenciális olvasás
BC = SIZE BC = sikeresen beolvasott bájtok száma
DE = MFCB DE = MFCB
IX = TRC IX = TRC a következő bájtra mutatBeolvassa a megadott számú byte-ot a file-ból a "diszk átviteli" címmel kezdődő memóriaterületre. Max. 64k olvasható; ".OV64k" hiba történik, ha az IX és a BC regiszterpárok tartalmának összege túlcsordul a 3. memórialap tetején. Az FCB-t előzőleg meg kell nyitni.
A file-on belüli pozíciót az FCB file-mutató mezője határozza meg, amely minden olvasás után aktualizálódik, s így a következő byte-ra mutat. Ha a funkció hibát jelez, a sikeresen olvasott byte-ok száma kisebb lehet, mint a két byte-szám. Ez a visszaadott szám minden hibajelzés esetén helyes, kivéve a ".STOP" és ".ABORT" hibákat. Ha a file végén túl próbálunk meg olvasni, ".EOF" hibajelzést kapunk.16. Szekvenciális írás
BC = SIZE BC = sikeresen kiírt bájtok száma
DE = MFCB DE = MFCB
IX = TRC IX = TRC a következő bájtra mutatA diszk átviteli területről a megadott számú byte-ot beírja a file-ba. Maximum 64k írható, és ".OV64k" hibajelzést kapunk, ha a BC és az IX regiszterpárok összege túlcsordul a 3. memórialap tetején. Ha a VERIFY rendszerváltozó értéke "0", akkor a fölírt adatokat automatikusan ellenőrzi. Az FCB-t előzőleg meg kell nyitni.
A file-on belüli pozíciót az FCB file-mutató mezője határozza meg, amely minden írás után aktualizálódik, s így a következő byte-ra mutat. Ha hibajelzéssel tér vissza a funkció, akkor a sikeresen fölírt byte-ok száma kisebb lehet, mint az írni kívánt byte-szám. A visszaadott szám minden hibakód esetén érvényes, kivéve a ".STOP" és az ".ABORT" hibajelzéseket.
Ha az írás túlhalad a file végén, akkor a file számára szükség szerint további lemezterületeket foglal le, a file-méretet pedig aktualizálja. Ha az írás a file végén túl kezdődik, akkor a "hézag" betöltésére a lemezterületet lefoglalja, de nem inicializálja. Ha nincs elég hely a lemezen a teljes írási művelet számára, akkor a ".DKFUL" hibajelzéssel tér vissza és egyáltalán nem ír fel adatot, még akkor sem, ha az adatok egy része számára volna hely.17. Szekvenciális írás 0 feltöltéssel
BC = SIZE BC = sikeresen kiírt bájtok száma
DE = MFCB DE = MFCB
IX = TRC IX = TRC a következő bájtra mutatEz a funkció azonos a fent ismertetett "írás file-ba" funkcióval. Az egyetlen különbség, hogy ha az írás a file végén túl kezdődik, akkor a "hézag" kitöltésére lefoglalt lemezterületet 0-val írja végig.
18. Szektorok olvasása (logikai szektor)
DE = SZEK DE = következő SZEK
H = SZEKN H = beolvasott SZEKN
L = MEGH L =MEGH
IX = TRC IX = TRC a következő bájtra mutatA megadott szektorokat beolvassa a diszkről az IX-ben adott címtől kezdődő memóriaterületre. Max. 64k olvasható, és ".OV64k" hibajelzést ad, ha az IX tartalmának és a beolvasandó szektorok összesített byte-számának összege túlcsordul a 3. memórialap tetején.
Hiba előfordulásakor a beolvasott szektorok száma kisebb lehet, mint a kért szektorok száma. A visszaadott szám minden hibakód esetén érvényes, kivéve a ".STOP" és ".ABORT" hibajelzéseket. Hiba esetén ismételt próbálkozások történnek, s a diszk-hibák keresztülmennek a normál ABORT / RETRY / IGNORE hibakezelő szubrutinon.19. Szektorok írása (logikai szektor)
DE = SZEK DE = következő SZEK
H = SZEKN H = kiírt SZEKN
L = MEGH L = MEGH
IX = TRC IX = TRC a következő bájtra mutatA megadott szektorokra fölírja a diszk átviteli területen levő adatokat. Max. 64k írható, és ".OV64k" hibajelzést ad, ha az IX tartalmának és a fölírandó szektorok összesített byte-számának összege túlcsordul a 3. memórialap tetején.
Hiba előfordulásakor a felírt szektorok száma kisebb lehet, mint a felírni kívánt szektorszám. A visszaadott szám minden hibakód esetén érvényes, kivéve a ".STOP" és ".ABORT" hibajelzéseket. Ha a "VERIFY" rendszerváltozó értéke 0, akkor automatikusan szektor ellenőrzés történik.20. Rendelkezésre álló meghajtók lekérdezése
DE+HL = 26 bites szám amelyik bit 1 az a meghajtó létezik
L 0. bit = A
L 1. bit = B
...
L 5. bit = E
stb.A logikai vektor egy 26 bites szám, amely azt adja meg, hogy mely logikai meghajtók használhatók. Az UPM-töl eltérően a rendszer valamennyi meghajtója állandóan "él", így a login vektor egyszerűen azt mutatja, hogy mely meghajtók vannak jelen a rendszerben. A 0. bit az A: meghajtónak felel meg, és így tovább ; az "1"-be állított bitek jelzik a meglevő meghajtókat.
21. Allokációs információ
B = MEGH B = szektor/cluster
DE = cluster/lemez
HL = szabad cluster
IX = meghajtó adatterület+8E funkció fő felhasználása információ szerzés a diszk méretéről és a szabad terület nagyságáról. Az alapegységenkénti szektorszám, amit a B regiszteren kapunk meg, mindig 2 egész kitevőjű hatványa, a szektorméret pedig mindig 512 byte. Így az alapegység mérete 512 byte-tól 64k-ig terjedhet. A szabad hely fölmérése néhány másodpercet igénybe vesz, mert a diszken az egész FAT-ot meg kell vizsgálni.
Az IX-ben visszaadott mutató felhasználásával részletesebb információt kaphatunk a lemezformátumról:
IX-1 aktuális egységszám (1...26) IX-0 fizikai egységszám (1...26) IX+1 belső használatra IX+2 alapegység maszk (alapegységenkénti szektorszám - 1) IX+3 alapegység eltolás (az alapegységenkénti szektorszám 2-es alapú logaritmusa) IX+4,5 az első FAT szektor szektorszáma IX+6 a FAT példányok száma IX+7 a szabad bejegyzések száma az utolsó szektorban IX+8 a kiindulási directory első szektorának szektorszáma IX+9 az egy FAT-ban levő szektorok száma IX+10,11 ua. mint az IX+8 IX+12,13 az első adatszektor szektorszáma IX+14,15 az adat-alapegységek száma + 2 IX+16 "piszkos diszk"-jelző : 0 = tiszta ; 1 = piszkos IX+17-20 kötet azonosító IX+21 hordozó byte 22. Fizikai meghajtó lekérdezés (az 1.0-ás verzió nem kezeli)
B = MEGH B =MEGH
C = FMEGHEz a funkció logikai, vagy fizikai egységszám konvertálására szolgál fizikai és aktuális meghajtószámmá. A logikai egységszámok azok, amelyeket a felhasználó begépel a parancsokban, és amelyeket az FCB-be teszünk. Ezeket a FISH fizikai egységszámokká konvertálja az ASSIGN műveletekben megadott összerendelések szerint. Ez egy egyszerű konverzió és, ha nem volt ASSIGN akkor a logikai és fizikai meghajtószámok megegyeznek.
A fizikai egységszámokat aktuális egységszámokká konvertálja a FISH a MAPDISK műveletekre megadott összerendelések szerint. Egy meghajtós rendszerben a "B:" fizikai meghajtó automatikusan az "A:" aktuális meghajtóhoz rendelődik, így két diszk érhető el az egy meghajtón. Az aktuális egységszámok közvetlenül meghajtókat jelentenek, így az 1...4 aktuális egységszámok mindig azt a négy meghajtót jelentik, amelyeket a DISKIO kezelni tud.
Ez a funkció olyan parancsok számára készült, amelyek a DISKIO-t közvetlenül használják, különösen, ha emellett FISH funkcióhívásokkal is fordulnak a diszk-hez. A felhasználótól kapott meghajtószám logikai egységszámnak tekintendő, és közvetlenül átadandó a FISH-hívásoknak. A DISKIO viszont meghajtó maszkot vár, amely az 1...4 aktuális meghajtóknak felel meg. Ezeket a felhasználótól kapott logikai meghajtószámokat aktuális fizikai meghajtószámmá kell konvertálni, mielőtt meghajtómaszkot készítenénk belőle, s ezt átadnánk a DISKIO-nak. Ez biztosítja, hogy minden érvényes ASSIGN és MAPDISK művelet érvényre jut.
Az egységleíró terület, amelyet az IX-től kapunk meg, azonos a "lemez foglaltsági információ beolvasása" funkciótól visszakapott eredménnyel. Megjegyzendő azonban, hogy ez a funkció nem vizsgálja meg a lemezt, mielőtt visszaadná a mutatót, így lehet, hogy számos mező nem lesz kitöltve. Ha a funkció hívása előtt közvetlenül a diszk-hez fordulunk, akkor az egységleíró mezők érvényesek lesznek.23. memóriaterület foglalása
Ezzel kisebb memóriaterületet lehet átmenetileg lefoglalni, BC-ben a kért méret, visszatéréskor B a szegmensszám, DE pedig a terület fölé mutat.
A trükk itt az, hogy a FISH egy jelzőbiten keresztül üzen a DISK perifériának, hogy ne normál fájlkezelő módban működjön, hanem csak foglalja le a megadott méretet csatorna-pufferként. Így nyit meg egy csatornát (szabad csatornaszámot keres hozzá), a kapott csatorna-puffer címét adja vissza a felhasználónak. A területet addig használhatjuk, amíg nem történik a csatornák bezárásával járó művelet.24. Meghajtó beláncolása
B=szegmensszám,
DE=cím mutat a leendő meghajtó leíróblokk helyére, ahol a következő adatokat kell elhelyezni:
0: belső egység darabszám
1-2: kezelőprogram címe
3: kezelőprogram szegmensszáma
A megadott területnek RAM-ban kell lennie, méret 3 bájt (a következő leíróblokkra mutató cím számára) + annyiszor 60H bájt ahány belső egységet megadtunk. A leíróblokkban a kezelőprogram RAM területének a híváskor megadott szegmens: cím lesz bejegyezve. Ezzel a hívással nem csak hidegindításkor, hanem akármikor tudunk meghajtót beláncolni!25. Mapdisk megadás
B = MEGH BC=0
C = FMEGH26. Assign megadás
B = MEGH BC=0
C = FMEGHEz a funkció a parancsértelmező számára készült az ASSIGN parancs végrehajtásához. Ha egyik egységszám sem 0, akkor minden jövőbeni hivatkozás az első egységszámra konvertálódik, és a második egységszámra fog vonatkozni. Ha a második egységszám 0, akkor az első egységszám visszarendelődik önmagához. Ha az első egységszám 0, akkor minden előző ASSIGN művelet törlődik.
Megjegyezzük, hogy e funkció használata után a megnyitott FCB-k hirtelen másik lemezre fognak vonatkozni (mivel az FCB-ben levő egységszámok logikai egységszámok). Ennél fogva ajánlatos, hogy a funkció meghívásakor ne legyenek megnyitott FCB-k.27. A diskpufferek számának növelése
B regiszterben adjuk meg a pufferek új számát (max. 10 lehet), 0 esetén lekérdezés.
Ezt használja a BUFFERS parancs, ami eredetileg benne volt az EXDOS-ban (lásd 0.3), de később kiszorult belőle és csak az ISDOS-ban található meg.
Megjegyzés: ha kevesebbet adunk meg, mint amennyi jelenleg van, akkor se történik semmi, csak visszakapjuk az aktuális értéket, vagyis FISH-en keresztül csökkenteni nem lehet. Ez úgy oldható meg, hogy a FISH adat területen átírjuk a pufferek számát (IY+21H), majd kiadunk egy EXOS reset-et 20H-val, így újraszerkesztődik a periférialánc, ezáltal a pufferek számára memóriát foglaló '.' nevű periféria is újra lesz beláncolva, az általunk megadott puffer-mérettel.
Amikor a FISH 27 működik, az pluszban vesz fel még egy '.' nevű perifériát, a szükséges plusz pufferek foglalásához. Ez jól látható, ha az EPDOS DEVS parancsával kilistázzuk a periférialáncot a BUFFERS parancs használata után. Ha azonban kilépünk pl. BASIC-be az ISDOS-ból, már ismételten csak egy '.' lesz, mivel ilyenkor végrehajtódik egy EXOS reset, így újra láncolódnak a perifériák.28. RAMDISK létrehozás-törlés
B = Szegmensek száma (0 = törlés)29. Formázás
B = forma (F8-FF)
C = MEGH HL = MEGH adatterület
DE = pufferterület (6500 bájt)Ez a funkció formattálja a megadott meghajtóban levő lemezt, a "hordozó" byte által definiált módon. Nincs ellenőrzés arra vonatkozóan, hogy a lemez már formattált-e, a hívó programnak kell megbizonyosodni róla, hogy a felhasználó valóban formattálni akarja a lemezt. A funkció ellenőrzi, hogy az adott meghajtó alkalmas-e a kívánt formátumban való működésre, és szükség esetén 40-ben korlátozza a sávok számát, ill. 1-ben az oldalakét.
A hordozó-leíró byte olyan, mint a FATID byte a FAT elején és a boot-szektorban a port-MS-DOS2 lemezeken. A megformattált lemez boot-szektora egy véletlenszerű kötetazonosítóval jön létre. A FAT-ok és a directory inicializálódnak, és a lemeznek nem lesz kötet-azonosítója.
hordozó-leíró oldal szektor / sáv sáv / oldal0F8h 1 9 800F9h 2 9 800FAh 1 8 800FBh 2 8 800FCh 1 9 400FDh 2 9 400FEh 1 8 400FFh 1 8 4030. Fenntartva
File Control Block-ok (FCB-k) formátuma
KFCB: (használatba vétel előtt a területet nullázni)
00 FF (keresési FCB) 01-05 kötelezően 0 06 Keresési attribútum (csak VOL-ra) 07 Meghajtó (0 = aktuális) 08-0F Fájlnév > (lehet ? is) 10-12 Kiterjesztés 13-1C ? 1D-1E Logikai szektorszám 1F A katalógushoz tartozó szektorok száma: (DEC ciklusszámláló 1 = utolsó) 20 A szektorhoz tartozó fájlleírók száma (DEC ciklusszámláló 16 = 1. fájl) 21-2B ? 2C-2F Lemez azonosító (ID szám) MFCB: (megtalálva)
00 FE (meghatározott FCB) 01-05 0 06 Keresési attribútum 07 Meghajtó 08-0F Fájlnév (08-27 a beolvasott fájlleíró adatok) 10-12 Kiterjesztés 13 Fájl attribútum 14-1D 1E-1F Idő 20-21 Dátum 22-23 Kezdő cluster 24-27 Fájlméret 28-2B Fájlmutató 2C-2F Lemez azonosító (ID szám) MFCB: (megnyitva)
00 FE 01-05 0 06 Keresési attribútum 07 Meghajtó 08-12 Fájlnév + kiterjesztés 13 Attribútum 14-16 0 17-1A Fájl meglévő mérete (SIZE) 1B-1C Dátum 1D-1E Idő 1F ? 20 ? (ha bit 6 = 1 akkor írás történt) 21-22 Kezdő cluster 23-24 Aktuális cluster 25-27 Cluster számláló (0 = első) 28-2B Fájlmutató 2C-2F Lemez azonosító
Meghajtó adatterület: (60H méretű)
00 ? 0,2 01-02 Meghajtó RAM címe az 2. lapon (FISH IY) 03 Meghajtókezelő szegmensszáma 04-05 Meghajtókezelő címe a 3. lapon 06 ? (0 = létező meghajtó?) 07 Fizikai meghajtószám 08 Logikai meghajtószám 09 1-2 esetén csere ellenőrzés (64H>DEC 1/50 sec. időszámláló) 0A 0-1 0B 0-1 0C 1 0D 0 0E 2 0F 0 10 ROOT-DIR szektorok száma 11 FAT szektorok száma 12-13 0. cluster logikai szektorszáma 14-15 2. cluster logikai szektorszáma 16-17 legnagyobb lehetséges cluster + 1 18 0 19-1C Lemez azonosító (ID) 1D Formázás típusszám
A FISH ás EXOS változók összefüggése
64 (IY-5E) EXDOS-ROM szegmensszám 65 -5D P0 66 -5C P1 A transzfercím számoláshoz 67 -5B P2 68 -5A P3 69 -59 ECHO-flag 70 -58 VERIFY-flag 71 -57 aktuális meghajtó 72 -56 ISDOS-BOOT-DRV 73 -55 STEP-RATE 74 -54 DISK-CHANGE-FILE-flag 75 -53 ERROR-INP-csat 76 -52 ERROR-OUT-csat 77 -51 CLI-INP-csat 78 -50 CLI-OUR-csat 79 -4F DATE-TIME-forma 80 -4E ERROR-DISABLE-flag 81 -4D DISK-ERROR-code 82 -4C ISDOS-ERROR-code 83 -4B ISDOS-CLI-védelmi-flag 84 -4A RND0 85 -49 RND1 A VOL-ID-hez 86 -48 RND2 87 -47 RND3 88 -46 CLI-END-flag 89 -45 DISK-CHANGE-flag 90 -44 FAST-VIDEO-flag 91 -43 DIR-END-flag 92-99 -42-3B fenntartott terület -3A ERROR-seg -39 ERROR-prtL -38 ERROR-prtH
Hibakódok - hibaüzenetek
CFh .NOFIL File not found a file nem található BFh .NOUPB belső hiba BDh .ICMD belső hiba BCh .IUNUM belső hiba BBh .ISECT belső hiba BAh .NRDY Not ready nem üzemkész B9h .VERIFY Verify error hiba az ellenőrzésnél B7h .SNF Sector not found a szektor nem található B6h .WPROT Write protected disk írásvédett lemez B5h .UFORM Unformatted disk formálatlan lemez B4h .NDOS Not a DOS disk nem DOS lemez B3h .WDISK Wrong disk rossz lemez B2h .WFILE Wrong disk for file rossz lemez a file számára B1h .WDRV Insert disk for drive x: helyezzen be lemezt az x: meghajtóba B0h .ICALL érvénytelen FISH funkciószám AFh .IDRV Invalid drive érvénytelen meghajtó AEh .IPARM Invalid parameter érvénytelen paraméter ADh .DRFUL Root directory full a gyökérkönytár megtelt ACh .DKFUL Disk full a lemez megtelt ABh .DUPF Duplicate file name kétszeres file név AAh .NODIR Directory not found a directory nem található A9h .DIRE Invalid directory move érvénytelen directory áthelyezés A8h .IPATH Invalid pathname string érvénytelen útvonalnév-string A7h .FILRO Read only file csak olvasható file A6h .IFNM Invalid filename érvénytelen file név A5h .DIRNE Directory not empty a directory nem üres A4h .ABORT Disk operation aborted a lemezművelet félbeszakadt A3h .IFAT Egy, a FAT táblából beolvasott érték kívül esik a lemez címtartományán. A0h .IFCB Érvénytelen volt a FISH-nek átadott FCB 9Fh .INP Invalid number of parameters érvénytelen számú paraméter 9Eh .DOT Invalid . or .. operation érvénytelen . vagy .. művelet 9Ch .BFUL Command too long túl hosszú parancs (max. 128 karakter) 9Bh .OV64k A 64k-s területen túlnyúló mennyiségű adatot próbáltunk meg írni/olvasni 9Ah .FILE A file alapegységlánca túl rövid a directory-bejegyzésben megadott mérethez. 99h .SYSX System file exists a rendszer-file létezik 98h .DIRX Directory exists a directory létezik 96h .NCOMP Incompatible disk nem kompatibilis lemez 95h .ICOPY File cannot be copied onto itself a file nem másolható önmagára A FISH hibakezelés átvétele: (IY-3A-38)
A rutin a 0. vagy az 1. lapon lehet. A szegmensszám nem nulla értéke esetén, minden FISH hibánál megkapjuk a vezérlést.
B = hibakód A = 0 - a hibakezelés visszaadása a FISH-nek
C = MEGH = 1 - ABORT
= 2 - RETRY
= 3 - IGNORE
= 4-255 - ABORT
HSoft & ZozoSoft - Enterpress 1993/6 - 1994/3-4
A különböző nyelvek közül az assembly programozás igényli a legtöbb időt és energiát. Egyszerű feladatoknál különösen kitűnik, hogy a perifériális INPUT/OUTPUT, főképpen a hibakezelés mennyi munkába kerül.
Vannak gyakran ismétlődő feladatok. Az ilyen rutinokat célszerű uniformizálni, és feladatuk szerint csoportosítani. A fáradtságunk gyorsan megtérül, mert csak egyszer kell őket megírni.
Az első rutinfájl a numerikus és sztringadatok kiírását hivatott könnyíteni. Az írás történhet a memóriába, ahol a kezdőcímet DE regiszterpárban tároljuk, és a visszatérés után a következő szabad bájtra fog mutatni. Másik lehetőségként a 4. EXOS változóval beállított alapértelmezésű) csatornára írhatunk. Visszatéréskor AF tartalmazza az EXOS hívás státuszát. A rutinok megőrzik a HL, az index,
és az alter regiszterek tartalmát.
Sztringek írása: A CALL hívást követő DEFB adatokat küldi el blokkírással az első nulla bájtig, majd visszatér az ezt követő címre. A rutinnal nulla bájtot nem lehet kiírni, viszont a hossz nincs korlátozva.
Numerikus adatok írása: A számok mérete 8 vagy 16 bites lehet. Az egy bájtost az akkumulátorba, a két bájtost a HL regiszterpárba kell helyezni. A bináris számokat kiírhatjuk decimális vagy hexadecimális, a BCD számokat pedig a hexadecimális rutinnal. (A karakterek elküldése bájtonként történik.)
A szövegfájlt célszerű az ASMON editorával elkészíteni. Szeretném felhívni a figyelmet itt néhány hibalehetőségre: Aki 80 karakteres (ASMEN) editorral dolgozik, az INCLUDE fájlokat ne mentse ki CTR-I-vel (intelligens gyorsmentés), mert fordításnál hibát okoz. Valamilyen hiba folytán a mentés gyakran csonka. Ezt elkerülhetjük, ha az editorból F8-al kitépünk, majd E-vel visszalépünk. Ekkor F4-el választhatunk mentést (TURBO SAVE). Fájlnévnek "NUM_STR.ASM"-et adjunk.
Ha később valamilyen programunkban használni szeretnénk, INCLUDE NUM_STR.ASM direktivóval egyszerűen hozzáfordítjuk a kódunk végéhez. Példaképpen mellékelem a DUMP.ASM listát, mely több rutinszolgáltatást is igénybe vesz. A fordítás előtt [Z]-vel beállítjuk az assembler opciókat:
Assembly listing: OFF
List conditions: NO
Force Pass 2: NO
Memory assembly: YES
Memory offset: 0
Object file name:
[A]-val fordítunk. Hibátlan esetben [G]-vel megadjuk a 3000-s kezdőcímet, majd Enter-rel lefuttatjuk a kódot.
Végül a lényegesebb rutinnevek listája:
DECHLPRINT | 16 bites decimális kiírás |
DECAPRINT | 8 bites decimális kiírás |
DECHLDE | 16 bites dec. memóriaírás |
DECADE | 8 bites dec. memóriaírás |
HEXHLPRINT | 16 bites hexadecimáis kíírás |
HEXAPRINT | 8 bites hexadecimális kiírás |
HEXHLDE | 16 bites hex. memóriaírás |
HEXADE | 8 bites hex. memóriaírás |
STRPRINT | sztring kíírás |
STRDE | sztring memóriaírás |
APRINT | akkumulátor kiírás |
BPRINT | B-regiszter kiírás |
SPPRINT | szóköz kiírása |
CRLFPRINT | újsorjel kiírása |
JPHL | vezérlésátadás |
JPIX | vezérlésátadás |
JPIY | vezérlésátadás |
A NUM_STR.ASM rutinját egy újabbal bővítjük. A neve ERROR.ASM. Hívásakor az akkumulátorban lévő hibakód szöveges megfelelőjét az alapértelmezésű csatornára írja. A rutin a hibaszöveget EXOS 28-as hívással kéri le. DE regiszter a hibapufferre mutat. Visszatéréskor az első bájt megadja a hosszúságot, melyet a hibasztring követ. Szöveges magyarázat hiányában (nulla hossz), decimális és hexadecimális formában kiírja a hibakód számát. A rutin valamennyi regiszter
tartalmát megőrzi. 64 bájtos RAM-puffert igényel, melynek a kezdőcímét ERRBUFF néven kell megadni.
A tesztelésére ASMON alatt futó kódot írtunk: HIBALIST.ASM. Kiíratjuk a 128-255 közötti EXOS-hibaüzeneteket a képernyőre. A [Z]-opcióval beállítjuk:
Memory assembly YES
Memory offset 0
[A]-val fordítunk, [G]3000-rel futtathatjuk.
HSoft - Enterpress 1992/2.
Sprite
kezelés ENTERPRISE-on
A sprite-ok, másnéven szellemek vagy manók, a számítógépes játékok legfőbb
alkotóelemei, ezért azokban a gépekben, amelyeket főleg játékra terveztek egy
külön hardver gondoskodik a mozgatásukról. Sajnos az ENTERPRISE nem büszkélkedhet
ilyen képességekkel, tehát kénytelenek vagyunk programból megvalósítani ugyanezt.
Megpróbálom néhány BASIC és ASSEMBLY rutin segítségével bemutatni a sprite-kezelés
módszereit.
Az első és egyben legprimitívebb eljárás (amelyet általában a kezdő BASIC-programozók
alkalmaznak előszeretettel), hogy kirajzoljuk a hátteret majd erre kirakjuk
a manókat az aktuális pozíciójukba. Ezután elvégezzük a többi szükséges műveletet
(billentyűzetfigyelés, ellenőrzések, számítások stb.), majd letöröljük a képernyőt
és kezdjük elölről az egészet. Ez a módszer nagyon lassú, ezért az egész kép
villog, méghozzá nem is kis mértékben. De mivel az ENTERPRISE-nak olyan remek
videóchip-je van, mint a NICK, ezért még ezt a legősibb eljárást is megoldhatjuk
villogásmentesen, mégpedig egy háttérképernyő segítségével. A lényeg, hogy két,
méreteiben azonos videólapot nyitunk meg, amelyek közül mindig csak az egyiket
kapcsoljuk be, és a azon dolgozunk, amelyik nem látszik (ezt hívjuk háttérképernyőnek).
Miután mindent kiraktunk rá, egy DISPLAY utasítással átkapcsolunk erre a videólapra.
Ha mindent jól csinálunk a képernyőn semmi nem fog villogni, azonban a programunk
nagyon lassú és ezért élvezhetetlen lesz, ezért ezt a módszert csak olyanoknak
ajánlom, akik most ismerkednek a programozással.
A második lehetőség, hogy a sprite-ok szélein egy vagy több pixel szélességű
üres sávot hagyunk. Ha ezt úgy tesszük ki a képernyőre, hogy az előző fázis
helyétől csak annyi képponttal tér el az új pozíció ahány egység szélességű
üres sáv van a szélein, akkor ez teljesen letörli az előző fázis egyébként kilógó
részét. Mint látható ennél a módszernél nincs külön kirakás és törlés, hanem
mindkettő egyszerre hajtódik végre. Ezért ez az eljárás kellően gyors ahhoz,
hogy akár BASIC-ben is alkalmazhassuk. Legnagyobb hátránya, hogy nem lehet a
szellem mögött háttér mert mozgása közben azt is letörölné, a másik hibája,
hogy csak kis egységenként lehet mozgatni (maximum anníi ponttal amilyen széles
az üres sáv a szélén). Ezen hiányosságai ellenére BASIC-ben a legjobb megoldás
a sprite-kezelésre, persze csak akkor ha nem alkalmazunk hátteret. Sajnos az
ENTERPRISE BASIC-ben ezt a sprite kezelési módszert nem vagy csak nagyon körülményesen
lehet megvalósítani, ugyanis ha grafikus lapra írunk a PRINT utasítással akkor
az nem írja felül azt, ami kint van a képernyőn, hanem hozzámásolódik. Ezért
a manó szélein hagyott keret nem fogja letörölni az előző fázist.
A következő megoldás, amikor a manót úgy rakjuk ki, hogy össze XOR-oljuk a képernyőn
lévő háttérrel. Mivel ennek a logikai műveletnek az a tulajdonsága, hogy ha
egy értéket kétszer össze XOR-olunk egy másikkal, akkor visszakapjuk az eredetit,
ezért a sprite letörlése nagyon egyszerű, csak újra ki kell raknunk. A leírtakból
már látszik, hogy ismét két fázisból áll a művelet, tehát lassabb lesz, mint
az előző, de itt nyugodtan mozoghat a manó egy háttér előtt is, nem fogja azt
letörölni. Természetesen a XOR művelet miatt színes képernyőn a végeredmény
nem mindig a legszebb. Magasszintű programnyelvekben ez a legelterjedtebben
alkalmazott módszer. Egy BASIC nyelvű példaprogram az 1. listán látható, ami
alapján remélem mindenki számára világos lesz az eljárás.
100 PROGRAM "SPRITE.BAS" 200 GRAPHICS HIRES 16 120 SET KEY CLICK OFF 130 SET LINE MODE 3 140 LET SPRX=10:LET SPRY=5:LET E$=CHR$(154) 150 PRINT £101,AT SPRY,SPRX:E$ 160 LET LSPRX=SPRX:LET LSPRY=SPRY 170 LET JS=JOY(0) 180 LET SPRX=SPRX-((JS BAND 1)=1 AND SPRX<20)+((JS BAND 2)=2 AND SPRX>1) 190 LET SPRY=SPRY-((JS BAND 4)=4 AND SPRY<10)+((JS BAND 8)=8 AND SPRY>1) 200 IF LSPRX=SPRX AND LSPRY=SPRY THEN 170 210 PRINT £101,AT SPRY,SPRX:E$ 220 PRINT £101,AT LSPRY,LSPRX:E$ 230 GOTO 160 |
Devil - Enterpress 1992/5-6. |
.RADX
16 SPRX EQU 2 SPRY EQU 10 LINESIZE EQU 50 SPRITEDAT EQU 4000 MASKDAT EQU 4020 |
;sprite vízsz. mérete byte-ban ;sprite függ. mérete pontban ;videólap vízsz. mérete ;sprite memóriacíme ;maszk memóriacíme |
|
TOROL SPROFF KIRAK SPRON2 SPRON LASTSPR PUFFER |
LD HL,(LASTSPR) |
;az
elmentett ;képernyőadatok ;visszamásolása ;HL-be SPR cím ;HL'-be maszk cím ;BC'-be a puffer cím ;A-ba a kép megf. byte ;eltárolása a puffer-be ;le AND-elése a maszkkal ;a sprite hozzá OR-olása ;visszaírás a videóm. ; ciklus ismétlése ; X méretétől függően ;a következő sor ;címeinek kiszámítása ;ciklus ismétlése a SPR ;Y méretétől függően ;utoljára kirakott fázis ;puffer |
RAM-szegmensek
az EXOS alatt
Egy megbízható program, nem használhat hasraütéssel kitalált RAM szegmenet.
Erre több példa is rámutat. Más konfiguráció alatt is lehessen futtatni. Az
operációs rendszer is használhatja a RAM-szegmenst. (RAMDISK, bővítés, csatorna,
eszköz, stb.) Hiányozhat vagy hibás is lehet a kitalált szegmensszám. Egy szegmenset
az operációs rendszertől lehet igényelni, ill. felszabadítani.
EXOS 24 szegmens igénylés
Vssza: A = státusz, C = kiutalt szegmensszám
DE=EXOS határ (4000H)
Ha nincs már szabad szegmens, akkor a rendszer által használt alsó szegmenst utalja ki megosztott szegmensként. Az ilyen RAM-ot nem célszerű használni, mert leblokkolja az operációs rendszert. Hiába szabadul fel időközben egy teljes szegmens, még egy csatorna nyitást is "nincs szabad memória" hibával fog elutasítani. Ezért az ilyen RAM-ot azonnal fel kell szabadítani.
LD C,szegmensszám
EXOS 25 szegmens felszabadítás
Vissza: A = státusz
Az ilyen jellegű hívással, (USER) felhasználói szegmenskezelés történik. Ennek lényege, hogy a foglaltságuk megszűnik amint egy új felhasználói programot töltünk be, vagy egy rendszerbővítés átveszi a vezérlést, ill. 40H, 60H jelzőkkel végrehajtott EXOS RESET hatására. A perifériák által végrehajtott szegmens foglalás-felszabadítást az EXOS külön kezeli, és az előző akciók hatására sem szűnik meg a foglaltságuk. A rendszerbővítéseket szintén perifériaszegmensre tölti be az EXOS. Ha ilyen szegmensre van szükségünk, akkor a következő trükkel oldhatjuk meg.
LD
A,255 OUT (0B2H),A LD HL,0BF79H SET 0,(HL) EXOS 24 RES 0,(HL) |
;rendszerszegmens ;2. lapra ;kerneljelző ;periféria futás ;szegmens kérés ;felhasználói futás |
Sok esetben nem elegendő az EXOS által elérhető szegmenskezelés. PI. adott szegmensszám vagy video-szegmens igénylése. Ilyenkor az EXOS-szal kompatibilisen, magunknak kell a kiutalást kézbe venni. A bekapcsolást követően végrehajtott TESZT alatt történik a RAM-szegmensek könyvtárba vétele. A kezdőcím (255-ös szegmens) 0ABD0H, ide kerül a 0FFH szegmensbejegyzés. Innen lefelé (csökkenő címekkel és szegmensszámokkal) következnek a RAM-tesztet kiálló működő szegmensek. A végére a legalsó szegmensszám kerül, melynek megkülönböztetett szerepe van. Ez lesz a nulla szegmens. (Értéke kiolvasható a 0BFFCH címről.) Mivel e szegmenst nem lehet kiutalni, az értékét nullára módosítja az EXOS. A címét letárolja 0BF9CH-n. (A RAM-ok alatt lesz a ROM-ok könyvtára.) A 255-ös szegmens állandó rendszerszegmens lesz, melynek száma jelen esetben 1. A későbbi csatorna nyitások hatására számuk megnőhet. Az. EXOS nyilvántartást vezet a RAM-ok kiutalásáról.
BF9A | - EXOS határszegmens címe. |
BF9C | - RAM-szegmensek végcíme. |
BF9E | - A megosztott szegmensek száma. |
BF9F | - A szabad szegmensek száma. |
BFA0 | - A felhasználó által foglalt szegmensek száma. |
BFA1 | - A perifériák által foglalt szegmensek száma. |
BFA2 | - A rendszer által használt szegmensek száma. |
BFA3 | - A működő szegmensek száma. |
BFA4 | - A nem működő szegmensek száma. |
Az EXOS 0BF9A-n tárolja a határszegmens címét. Ez a legalsó, rendszer által használt szegmens. A RAM-szegmens lista az alábbi sorrendben épül fel.
(BF9C) | - 0 |
FELHASZNÁLÓ N=(BFA0) | |
PERIFÉRIA N=(BFAl) | |
SZABAD N=(BF9F) | |
(BF9A) | - RENDSZER N=(BFA2) |
ABD0 | - 255 |
Hsoft - Enterpress 1993 /1-2
A tömörített
programokról
Egy-két éve megjelentek a tömörített játék programok Aki szeret játszani, annak
előbb-utóbb gondot jelenthet a programok tárolása. A sok játék programhoz sok
adathordozó is kell. Ezen próbált segíteni a DTF tömörítő. Sikerrel!
A fájlok .DTF kiterjesztéssel szerepelnek. Betöltésük a DTF-betöltővel tovább
tart, mint a hagyományos játékok betöltése. Megjegyezzük, hogy a Zozotools 1.6
rendszerbővítő :DL parancsa sokkal gyorsabban tölti a DTF-fájlokat, mint az
eredeti DTF-betöltő.
Az EPDOS 1.5 rendszerbővítő is sikereket ért el a PACK neve tömörítőjével. Ehhez
készült egy külső rendszerbővítő, amely csak az EPDOS-al használható. Ennek
neve PP 1.1., amely jelentősen megkönnyíti a tömörítést. A tömörítendő fájlokat
kijelöljük az EPDOS 1-es módjában, majd az EXT-menüben kiadjuk a PP parancsot.
A céleszközön a tömörített fájl .PCK kiterjesztéssel jelenik meg. Betölteni
az EPDOS Start-menüjével lehet. Az EPDOS Start-menüje egyébként be tudja tölteni
a DTF, PCK-fájlokat, valamint elindítja a BASIC programokat, a VSAVE-vel elmentett
képeket és természetesen a gépi kódú programokat is.
Nézzünk egy példát: milyen hatékonyan tömörítenek a tömörítők? Kiszemelt programunk
a SPACE CRUSADE. 2009-ben IstvánV elkészítette a EPcompress-t és a DTF továbbfejlesztett változatát is. A táblázatban ezek is szerepelnek.
Eredeti méret: 115 464 byte (Töltési idő: 15 sec.)DTF-el tömörítve: 61 127 byte (Töltési idő: 60 sec.)PACK-al tömörítve: 68 750 byte (Töltési idő 15 sec.)DTF -p 1 5: 59 364 byte (Töltési idő: 22 sec.)DTF -lz: 47 848 byte (Töltési idő: 8.5 sec.)DTF -lz2: 46 237 byte (Töltési idő: 14.8 sec.)
Megjegyezzük, hogy a kész DTF-fájlhoz még egy betöltőt is kell írnunk. A PACK-kal viszont saját magunk tömöríthetjük programjainkat. A DTF-tömörítőről csak annyit: használata rendkívül körülményes, felhasználói felülete egyáltalán nincs. A kész DTF-programokról pedig csak annyit: ha eszünkbe jut, hogy annál a játéknál kevésnek bizonyul a 3 élet... ...nem tudunk semmit tenni! A PACK-nál viszont ez nagyon könnyen megoldható.
Enterpress 1993 /1-2
Hogyan is működik a DTF tömörítő?
A DTF tömörítés két menetben történik:
Először az egymás után ismétlődő azonos byte-okat cseréli egy 3 byte-os kódra (RLE tömörítés), amely egy jelzőbyte-ból (ami tetszőleges érték lehet és a fejlécben tárolódik), az ismétlődő byte-ok számából (ha 256 byte ismétlődik, akkor 0-t kell tárolni), és az ismétlődő byte értékből áll. Ennek természetesen csak akkor van értelme, ha a 3 byte-os kód rövidebb, mint az eredeti sorozat, azaz (statisztikai tömörítés nélkül) a sorozat hossza legalább 4 byte. Azonban ha a bemeneti adatban a jelzőbyte fordul elő, akkor azt mindig sorozatként kell kódolni, még akkor is, ha ez méretnövekedést eredményez. Ezért a jelzőbyte értékét célszerű úgy választani, hogy ez a méretnövekedés a legkisebb legyen (erre a legegyszerűbb, de nem mindig optimális megoldás a legritkább byte használata).
A TOM formátum csak az előbb leírt RLE tömörítést használja, a fejléc a tömörített adat és a jelzőbyte együttes mérete 2 byte-on tárolva (az alsó byte az első), ezt a jelzőbyte követi, majd végül a tömörített adat.
DTF-nél viszont az RLE tömörítés után van még egy második menet is, amely minden lehetséges byte értékhez hozzárendel egy bitsorozatot, ami nem fix 8 bit méretű, hanem a gyakori byte-ok rövidebbek, a ritkák pedig hosszabbak lesznek. Ezzel a statisztikai tömörítéssel további méretcsökkenésre van lehetőség. Az optimális kódolt byte méret elvileg kiszámítható a gyakoriságból (log2(1/f) bit, ahol 'f' az előfordulási gyakoriság 0 és 1 között; tehát például ha egy byte 25% valószínűséggel fordul elő, akkor azt 2 biten érdemes tárolni, ha viszont csak 0.1% a valószínűsége, akkor kb. 10 biten). Azonban, mivel az egyszerűbb és EP-n is használható megoldásoknál csak egész számú bit használatára van lehetőség, az optimális kód keresése ennél valamivel nehezebb. Ha minden byte-hoz tetszőleges egész számú bitet lehetne rendelni, arra a Huffman algoritmus lenne használható.
A DTF kódolása viszont még egyszerűbb és korlátozottabb. Itt minden tömörített byte két részből áll: fix számú jelzőbitből, és azt követően a jelzőbitek értéke alapján egy táblázatban tárolt számú további bitből. Egy második táblázatban a lehetséges byte értékek találhatók, gyakoriság szerint csökkenő sorrendben. Egy egyszerű példa két jelzőbittel, ilyenkor az első táblázat mérete 4; ha "1,2,3,4" található a táblázatban:
Beolvasandó bitek száma |
Második táblázat pozíció |
Optimális előfordulási valószínűség |
1 2 3 4 |
0 - 1 2 - 5 6 - 13 14 - 29 |
12.5% 6.25% 3.125% 1.5625% |
Egy DTF formátumú adatblokk részletes leírása:
A DTF tömörítésű programok elején mindig egy TOM formátumú blokk van, ez a .com része a programnak, amelynek a 0. lapon el kell férnie. Ezt követi tetszőleges számú DTF adatblokk, amiket RST 28H hívásokkal lehet betölteni.
A legjobb eredményt István tömörítője éri el, nézzük meg, hogyan működik:
Érték |
Hosszúság kód |
Távolság kód |
|
2 - 4 - 8 - 16 - 32 - 64 - 128 - 256 - 512 - 1024 - 2048 - 4096 - 8192 - 16384 - 32768 - |
1 3 7 15 31 63 127 255 511 1023 2047 4095 8191 16383 32767 65535 |
0B 10xB 110xxB 1110xxxB 11110xxxxB 111110xxxxxB 1111110xxxxxxB 11111110xxxxxxxB 111111110xxxxxxxxB 1111111110xxxxxxxxxB 11111111110xxxxxxxxxxB 111111111110xxxxxxxxxxxB 1111111111110xxxxxxxxxxxxB 11111111111110xxxxxxxxxxxxxB 111111111111110xxxxxxxxxxxxxxB 1111111111111110xxxxxxxxxxxxxxxB |
0000B 0001xB 0010xxB 0011xxxB 0100xxxxB 0101xxxxxB 0110xxxxxxB 0111xxxxxxxB 1000xxxxxxxxB 1001xxxxxxxxxB 1010xxxxxxxxxxB 1011xxxxxxxxxxxB 1100xxxxxxxxxxxxB 1101xxxxxxxxxxxxxB 1110xxxxxxxxxxxxxxB 1111xxxxxxxxxxxxxxxB |
A hosszúsághoz tömörített sorozatnál egyet hozzá kell adni, mert a legrövidebb sorozat, amelyet ez a tömörítő ismételni tud, 2 byte-os. Ezen kívül a 2 byte-os sorozatok a távolságnál más kódolást használnak, amellyel a legnagyobb lehetséges érték 65535 helyett csak 510, ehhez viszont általában egy bittel kevesebb is elég, és így valamivel jobb tömörítési hatásfokot tesz lehetővé:
Érték |
Hosszúság kód |
|
1 - 3 - 7 - 15 - 31 - 63 - 127 - 255 - |
2 6 14 30 62 126 254 510 |
000xB 001xxB 010xxxB 011xxxxB 100xxxxxB 101xxxxxxB 110xxxxxxxB 111xxxxxxxxB |
Egy teljes "dtf -lz" adatblokk felépítése:
A tömörített adatot a végétől visszafelé haladva kell olvasni, és a kitömörített adat is az utolsó byte-tól visszafelé íródik. Ez azért van, mert a memóriában a betöltendő adatterület elejére kerül, és így ha a kitömörítés előre haladna, akkor felülírná a még feldolgozatlan bemeneti adatot. A "fordított" iránnyal viszont az írási pozíció kitömörítés közben fokozatosan közeledik az olvasási pozícióhoz, és a befejezéskor éri el. A biztonság kedvéért azonban van egy 2 byte-os olvasási puffer is, arra az esetre, ha nehezen tömöríthető adatnál az írási pozíció átmenetileg megelőzné az olvasási pozíciót egy-két byte-al.
A tömörített adat részletesebben:
És most a betöltő rutin leírása, amelynek a belépési pontja 0028H (RST 28H), és csak egy bemeneti paramétere van, a DE regiszter, amely a betöltés kezdőcíme. A csatornaszám mindig 1, és az adatblokk hosszát a fent leírt módon a tömörített file-ból olvassa:
0028
002B
002C
002D
002ECD BE 00
AF
6F
67
18 38CALL 00BE
XOR A
LD L, A
LD H, A
JR 0068
Itt az első CALL utasítás beolvas egy 16 bites értéket a BC regiszterbe, ez lesz a file-ból olvasandó tömörített adatblokk mérete. A HL regiszter és a Carry jelzőbit törlése után a rutin folytatására ugrik (az EXOS által foglalt 30H-5FH területen nincs betöltő kód).
A fent meghívott rutin:
00BE
00C1
00C2
00C3
00C5
00C7
00C8
00C9CD C2 00
68
D5
3E 01
F7 05
D1
4D
C9CALL 00C2
LD L, B
PUSH DE
LD A, 01
EXOS 05
POP DE
LD C, L
RET
Az RST 28H folytatása:
0068
006A
006D
006E
0070
0073
0074
0075ED 52
22 09 00
3C
F7 06
CD BE 00
79
B0
28 EBSBC HL, DE
LD (0009), HL
INC A
EXOS 06
CALL 00BE
LD A, C
OR B
JR Z, 0062
Itt először kiszámítja a -DE értéket (az előbbi HL, A, és Carry törlés ezt készítette elő), és tárolja egy LD HL, n utasítás paramétereként, amely majd azt fogja ellenőrizni, hogy a kitömörítés befejeződött-e. Majd EXOS 6 hívással beolvassa az 1-es csatornáról az egész tömörített adatot a kezdőcímre (a BC-ben már a tömörített méret van).
Mivel a tömörített adat a betöltendő terület elejére került, a kitömörítésnek az adat végétől visszafelé kell majd haladnia a kezdőcím felé, hogy a még feldolgozatlan byte-ok ne íródjanak felül.
A tömörített blokk beolvasását követi egy újabb 16 bites érték olvasása, amely a tömörítetlen és tömörített méret közötti különbség. Ha a tömörítő nem tudott méretcsökkenést elérni, akkor az egész adatblokkot egyszerűen tömörítetlenül tárolja, a különbség nulla lesz, és a rutin futása itt befejeződik, és ide ugrik a 62H címre:
0060
0061
0062
0063
0064
0065
0066
0067D1
D1
6B
62
AF
4F
FB
C9POP DE
POP DE
LD L, E
LD H, D
XOR A
LD C, A
EI
RET
Ez az RST 28H-ból a visszatérés, a DE-ben és HL-ben az utolsó betöltött byte utáni cím lesz, az AF és BC regisztereket pedig sikeres EXOS 6 hívásnak megfelelően állítja be (azért csak a C-t törli, mert itt a BC már nulla, a másik lehetséges helyen, ahonnan ide lehet ugrani, pedig a B mindig nulla). Szintén itt történne a keretszín nullára állítása, ha a keretcsíkozás engedélyezve lenne.
A két POP DE-nek csak a tömörített formátum utáni visszatérésnél van jelentősége, az első egy visszatérési címet töröl.
Az RST 28H folytatása tömörített formátum esetén (BC > 0)
0077
0078
0079
007A
007B
007C
007D
007E
007F
0080F3
D5
D9
E1
D9
EB
09
E5
2B
EBDI
PUSH DE
EXX
POP HL
EXX
EX DE, HL
ADD HL, BC
PUSH HL
DEC HL
EX DE, HL
Letiltja a megszakításokat (kisebb sebességnövekedés), a HL' regiszterben tárolja az utolsó beolvasott byte utáni címet (ez lesz majd a tömörített adat olvasási címe), ehhez hozzáadva a méretkülönbséget kiszámítja az utolsó kitömörített byte utáni címet és tárolja a veremben (ahonnan majd a fenti második POP DE utasítás fogja olvasni), és a DE regiszter, amely az aktuális írási cím, pedig ennél eggyel kevesebb lesz.
0081
008401 01 10
DFLD BC, 1001
RST 18
Itt a C regiszter a bitek olvasásához kell, minden tömörített bit beolvasásakor ez a regiszter léptetődik jobbra, és a bit a Carry-be kerül. Azért 1 a kezdőértéke, mert ez a bit jelzi, hogy mikor fogyott el az összes bit; ha a jobbra léptetés eredménye nulla, akkor előbb új byte-ot kell beolvasni, majd megint jobbra léptetni úgy, hogy a legfelső bitnek 1 lépjen be. Az 1 tehát azt jelenti, hogy a regiszter üres, és az első bitnél új byte-ot kell majd olvasni.
Az RST 18H a B regiszternek megfelelő számú bitet olvas a HL regiszterbe egy 1 bit után, tehát pl. B=3 esetén HL=1xxxB lesz. A B 0 is lehet, ilyenkor mindig 1 a visszatérési érték.
Itt ennek csak az a célja, hogy 16 bitet, azaz két byte-ot olvasson, hogy az olvasáshoz használt két byte-os puffer (a BC' regiszter) feltöltődjön.
0085 CF RST 08
Az RST 08H egy hosszúság paramétert olvas tömörítetlen sorozathoz - ez a fent leírt kitömörítő ciklus első pontja.
A hosszúságok kódolásának a lényege, hogy először annyi 1 bit van, amennyi bitet az RST 18H-nak be kell majd olvasnia, majd egy 0 bit, végül pedig a beolvasandó bitek (lásd fent).
0008
000B
000C
000E21 00 00
19
38 03
18 50LD HL, 0000
ADD HL, DE
JR C, 0011
JR 0060
Itt először annak az ellenőrzése történik, hogy a kitömörítés befejeződött-e már. Az LD HL utasítás paramétere valójában a még az RST 28H elején kiszámított -KEZDŐCÍM. Tehát ha a következő byte írási címe már kisebb, mint a kezdőcím, akkor a kitömörítés befejeződött. Érdemes megjegyezni, hogy ez a megoldás nem működik akkor, ha a 0000H címre is töltődne adat.
Az RST 08H feltétezi, hogy a hívásakor a B regiszter 0.
0010
0011
0013
001604
CB 39
CC 86 00
38 F8INC B
SRL C
CALL Z, 0086
JR C, 0010
Itt történik a hosszúság paraméter elején az 1 bitek számolása. A CALL 0086H tömörített byte olvasását végzi, ha a C regiszterből elfogytak a bitek. A B regisztert a ciklus minden beolvasott 1 bit után növeli.
0018
0019
001C
001D
04
21 01 00
05
C8INC B
LD HL, 0001
DEC B
RET Z
Ez az RST 18H rutin, amely a fent leírt módon B bitet olvas a HL regiszterbe. Először ellenőrzi, hogy a B nem 0-e: ha igen, akkor a HL inicializálása után azonnal visszatér.
Végül a bitolvasó ciklus:
001E
0020
0023
0025
0027
CB 39
CC 86 00
ED 6A
10 F7
C9
SRL C
CALL Z, 0086
ADC HL, HL
DJNZ 001E
RET
Megjegyzendő, hogy a Z bit visszatéréskor 1, ha híváskor a B 0 volt, egyébként (szabályos bemeneti adat esetén, azaz ha B <= 15) mindig 0. Ezt a kód máshol felhasználja.
A tömörítetlen sorozatot másoló ciklus, egyben tömörített byte olvasása a C regiszterbe (a Carry bittől függően: az RST 08H/18H mindig Carry=0-val tér vissza, a C regiszterből az utolsó bitet kiléptető SRL utasítás viszont beállítja a Carry-t):
0086
0087
0088
0089
008A
008B
008C
008E
008F
0090
D9
78
41
2B
4E
D9
30 03
1F
4F
C9
EXX
LD A, B
LD B, C
DEC HL
LD C, (HL)
EXX
JR NC, 0091
RRA
LD C, A
RET
Itt a BC' regiszter a 2 byte-os bemeneti puffer, és a tömörített adat olvasási címe a 007AH-nál inicializált HL' regiszter. Ha lenne keretcsíkozás, akkor az olvasott byte-ot a 81H portra is kiírná.
Ha nem a C regiszter feltöltése történik (Carry=1), akkor folytatódik a másoló ciklus:
0091
0092
0093
0094
0095
0096
12
1B
2B
7D
B4
20 EE
LD (DE), A
DEC DE
DEC HL
LD A, L
OR H
JR NZ, 0086
Kiírja az olvasott byte-ot, csökkenti az írási címet, és folytatja a következő byte-al, amíg a HL-ben tárolt hosszúság elfogy. Érdekesség, hogy a tömörítetlen byte-okat nem bitenként olvassa, hanem egyszerűen a következő byte-ot a bemeneti adatból - így ugyan a bitek "kevert" sorrendben vannak, és bonyolultabb a file írása, viszont azonos file méret mellett egyszerűbb és gyorsabb lehet a kitömörítő.
Tömörítetlen sorozat után mindig egy tömörített következik:
0098
0099
CF
E5
RST 08
PUSH HL
Ez szintén hosszúság olvasással kezdődik (amit egyelőre elment a verembe), de itt a hosszúsághoz hozzá kell majd adni egyet, mert a legrövidebb sorozat 2 byte-os.
Tömörített sorozatnál természetesen van egy távolság paraméter is, amelynek a dekódolása valamivel bonyolultabb. A formátum különböző 2 byte-os, és hosszabb sorozatoknál. Az első esetben előbb be kell olvasni 3 bitet, majd az így kapott értéknél eggyel több bitet olvasni RST 18H-val, és végül az eredményből kivonni egyet; így csak 1 és 510 közötti távolság tárolható, viszont kevesebb biten, mint a hosszabb sorozatoknál. Azoknál ugyanis egyszerűen 4 bitet kell olvasni, majd azzal az értékkel (0-15) meghívni az RST 18H-t; ez 1 és 65535 közötti távolságot tesz lehetővé, de általában eggyel több biten.
009A
009B
009D
68
06 04
28 16
LD L, B
LD B, 04
JR Z, 00B5
Először törli az L regisztert (a B RST 18H után mindig 0), majd a B-t "hosszú" sorozatot feltételezve 4 bitre állítja. Azonban, ha 2 byte-os a sorozat (Z=1), akkor ez történik:
00B5
00B8
00B9
00BA
00BB
00BC
CD 25 00
2C
45
DF
2B
18 E6
CALL 0025
INC L
LD B, L
RST 18
DEC HL
JR 00A4
Ez először ráugrik a bitolvasó ciklus DJNZ utasítására, amely így csak 3 bitet olvas 4 helyett, majd az olvasottnál eggyel több bitet léptet 1 után a HL regiszterbe. Végül a távolság értéket eggyel csökkenti, hogy a tartomány 2-511 helyett 1-510 legyen.
A "hosszú" sorozatok távolság dekódolása, majd a tömörített sorozat másolása:
009F
00A2
00A3
00A4
00A5
00A6
00A8
00A9
00AB
CD 1E 00
45
DF
19
79
ED A8
C1
ED B8
4F
CALL 001E
LD B, L
RST 18
ADD HL, DE
LD A, C
LDD
POP BC
LDDR
LD C, A
A CALL 001EH beolvas 4 bitet az L regiszterbe, majd az ennek megfelelő számú (0-15) bit léptetése történik RST 18H hívással.
00A4H-nál már minden lehetséges hosszúságnál a dekódolt távolság van a HL regiszterben, tehát ezt a DE-hez (írási cím) hozzáadva - a fordított irány miatt SBC helyett ADD kell - kiszámítható a másolás forráscíme. Az LDD átmásolja az első byte-ot, ezt követően a hosszúság-1-et a veremből a BC regiszterbe olvasva az LDDR-el már befejezhető a másolás. Közben természetesen a bitléptetéshez használt C regisztert menteni kell.
00AC
00AE
00B1
00B3
CB 39
CC 86 00
30 D2
18 E3
SRL C
CALL Z, 0086
JR NC, 0085
JR 0098
Végül a ciklus befejezése: a jelzőbitnek megfelelően tömörítetlen (0085H) vagy tömörített (0098H) sorozattal folytatódik a kitömörítés. Ha itt már vége az adatnak, akkor a jelzőbit ugyan szemét lesz, de az értékétől függetlenül mindig hosszúság olvasás következik, amellyel befejeződik az RST 28H hívás.
IstvánV (2009)
A Bináris számokról
A digitális számítógépek és a digitális technikával készült alkatrészek olyan
áramkörökből állnak, amelyek lényegében kétállapotúak (binárisak). Mivel minden
alkatrész gyorsabban tudja felismerni az adandó funkciót, ha csak két esetleges
állapotot kell ismerniük. Kevesebb a zavarás és a hibalehetőség. Például ezért
találhatóak számítógépekben kizárólagosan csak digitális alkatrészek. Tehát
a számítógép által használt jelek binárisak, így a változói is binárisan értékelhetőek.
Számítások Bináris számokkal
Összeadás
A kettes számrendszer egyik előnye, hogy a műveletek végzése sokkal egyszerűbb
mint például a tízes számrendszerben. Ahhoz, hogy a tízes alapú számokat összeadjuk,
kifejezetten szükséges az iskolában megtanult "összeadás" táblázat.
De mivel a számok sorrendje a kettes számrendszer esetében nem közömbös, ezért
így több száz állapot lehetséges már igen kis tagszámú számsornál is az összeadáskor.
A kettes számrendszerben könnyű a dolgunk, mert csak a következő négy állapot
lehetséges:
00 + 00 = 00
01 + 00 = 01
00 + 01 = 01
01 + 01 = 10
Mindezt példával is szemléltetem, hogy érthető legyen, tízes számrendszerben
is elvégzem a műveletet:
11101 |
29 |
+01100 |
+12 |
=111001 |
=41 |
Az összeadást itt is a legkisebb helyértékű számjeggyel kezdjük,
és úgy haladunk jobbra.
Az iskolában valahogy így tanultunk számolni: Kilenc, meg kettő az tizenegy,
leírjuk az egyet, marad egy, kettő meg egy az három meg egy az négy. Leírom
a négyet, és a végeredmény negyvenegy.
Ez most is igaz. De itt most a jelenlegi példánkban így szól: Egy meg nulla
az egy, leírjuk az egyet, átvitel nincs. Nulla meg nulla az nulla, leírjuk a
nullát. És így tovább az előbbi táblázat szerint.
Most már tudunk bináris számokat összegezni, amint figyeltük nem kellett hozzá
csak néhány perc. Persze nem árt ezt még egy kicsit gyakorolni, és tízes számrendszerben
ellenőrizni számításaink pontosságát.
Kivonás
A kivonás a kettes számrendszerben lényegesen nehezebb mint az összeadás, de
nem is érdemes vele foglalkozni, mert a számítógépek teljesen másképp végzik;
de azért megemlítem: A kivonás ez esetben is úgy történik, mint a tízes számrendszerben.
Jobbról a legalacsonyabb helyértékű részről indulunk bal felé. A kivonást számjegyenként
kell elvégeznünk. Ha a kivonandó magasabb, akkor a magasabb helyértektől veszünk
kölcsön.
11011001 |
217 |
-01101111 |
-111 |
=01101010 |
=106 |
Szorzás
Most is hasonlóan végezzük a műveletet, mint a tízes alapnál. Minden lépésben
egy számjeggyel szorzunk végig minden értéket. A részszorzatot is eltolhatjuk
egy vagy több hellyel. Hogy látható legyen ez milyen egyszerű, megmutatom a
szorzótáblát:
A |
B |
A*B |
00 |
00 |
00 |
00 |
01 |
00 |
01 |
00 |
00 |
01 |
01 |
01 |
Szorzatok 2 hatványaival:
Most már minden baj nélkül tudunk szorozni 2 hatványaival. Egyszerű, hiszen
kettővel csak úgy kell szorozni, hogy a végeredmény után 0-át írunk.
11 x 10 = 110
Az osztást azért nem írom le, mert a számítógép teljesen másképp használja az
osztást mint mi. A bonyolultság szempontjából ez teljesen egyedülálló.
Piotr - Enterpress 1993/1-2
Cartridge
átalakítások
Az ENTERPRESS 91/5. számában jelent meg egy cikk "Mi
lakik a cartridge-ben" címmel, amely nem sok gyakorlati tanácsot adott,
pedig ha az EPROM-ha égethető programok hosszú listáját nézzük, akkor igencsak
elkellene egy kis "lakás bővítés". Kezdetnek vegyünk egy egyszerű
16 Kilobájtos EPROM helyet és nézzük, hogy lesz ebből 32 Kilobájtos:
Természetesen be kell kötni még egy címvezetéket, ehhez a foglalat 27-es lábáról
le kell kötni a +5 Volt-ot (általában a 28-as lábbal van összekötve), és rákötni
az A14-et, ez a művelet az eredeti EXDOS kártyákon nagyon egyszerű mivel tervezéskor
már gondoltak erre, ezért be is van jelölve az átvágás és az átkötés helye.
(De csak az 1.0-ás EXDOS-t tartalmazó kártyákban van 16 Kilobájtos EPROM, az
EXDOS 1.3 már 32 Kilobájtos.)
A kétnyelvű gépek kétszer 16 Kilobájtos cartridge-iben ezenkívül még gondoskodni
kell a megfelelő címkiválasztásról, hogy az EPROM-ok ne fedjék át egymást:
Ha 32 Kilobájtos EPROM-helyünk van, akkor kétféle dolgot csinálhatunk
belőle:
- 64 Kilobájtos EPROM helyet,
- 32 Kilobájtos SRAM helyet.
Elsőként nézzük a másodikat, mivel arról eddig még nem sokat írtak:
Mire is jó a cartridge-ben a statikus RAM? Ugyanúgy használhatjuk, mint egy
EPROM-ot, csak mivel RAM, ezért bármikor átírhatjuk a tartalmát: azt a (EPROM-ba
égethető) programot tölthetjük bele amelyikre éppen szükségünk van, és tartalma
hidegindítás után is megmarad (megfelelő bekötés esetén kikapcsolás után is!),
így nagy segítség lehet ilyen programok íróinak is.
Ha pedig nem EXOS 2.1-et, vagy valami más megfelelő gyorstesztet használunk,
akkor ha úgy tartja kedvünk, akár memória bővítésnek is felhasználhatjuk, esetleg
"szünetmentes" RAMDISK-nek!
Lássuk tehát mit fed a CMOS SRAM-ok EPROM-okhoz hasonló lábkiosztása:
Mivel RAM-ról van szó, ezért szükséges az írás engedélyező jel (R/W), ami a
SRAM (62256) 27-es lábára kerül, ezért az EPROM-on (27256) itt található A14
máshová kerül, mégpedig a SRAM 1-es lábára, amiről le kell kötni a +5 Volt-ot.
Ha azt is el akarjuk érni, hogy a SRAM ne veszítse el tartalmát, akkor gondoskodni
kell a tápfeszültségről a gép kikapcsolása után is. Ez megoldható elemmel is,
de szerintem egyszerűbb a kondenzátoros változat: kössünk egy kondenzátort a
SRAM 14-es és 28-as lába közé. A 28-as lábat egy diódával (a dióda "csíkos"
vége legyen a láb felé) kössük a +5 Volt-ra, különben a kondenzátor nem csak
a SRAM-ot látja el feszültséggel. Nem árt ha egy 4.7 Kohm-os felhúzó ellenállást
kötünk a +5 Volt (1-es láb) és a CE (20-as láb) közé, a bekapcsolásnál esetleg
bekövetkező adatvesztés ellen.
(Megjegyzem: ez a statikus RAM "buli" nem a legolcsóbb. A 62256-os
900-1000 forintba kerül.)
Most pedig lássuk a 64 Kilobájtos (27512) EPROM-okat: ismét
szükségünk lesz egy új címvezetékre, amit a foglalat 1-es lábára kötünk, de
előtte kössük le arról a +5 Volt-ot! Ha ezt az eredeti EXDOS kártyán játsszuk
el akkor kössük össze az EPROM (U2) 28-as lábát a WD (U1) 15-ös lábával, hogy
az is megkapja a tápfeszültséget. (Vigyázzunk arra, hogy az EPROM foglalatok
1-es és 28-as lába általában alul-felül össze van kötve!)
Ezt az átalakítást eddig (a cartridge-ben) csak az 1*32 Kilobájtos típuson lehetett
elvégezni, mivel egyetlen 27512-es EPROM kitölti a cartridge 64 Kilobájtos címtartományát.
De Zozosoft&Apuci úgy döntöttek, hogy akkor növeljük meg a címtartományt
128 Kilobájtra...
Ehhez már a gépet is át kell alakítani, tehát csak a bátrabb olvasók próbálják meg saját kezűleg elvégezni! Először az "emelet":
Akkor kell a cartridge-t engedélyezni, ha a legfelső 4 címvezeték
(A18-A21)=0, és ha az A16=1 (így különböztetjük meg a belső ROM-tól), így a
cartridge a 04h,05h,06h,07h,0Ch,0Dh,0Eh,0Fh szegmenseket jelenti.
Szükségünk lesz egy 74138-as IC-re, ami lehetőleg minél gyorsabb típusú legyen
(ALS, HCT, F), ennek az engedélyező és kiválasztó bemeneteire kötjük az A16,
A18, A19, A20, A21 címvezetékeket:
Ezek után nézzük a cartridge-et:
Erre a célra a 2*32 Kilobájtos (ha 2*16 Kilobájtos, akkor előbb alakítsuk át)
eredeti, vagy az alapján készült cartridge-ek használhatók.
Ahhoz, hogy az így kibővített cartridge-be helyezett programokat
meg is találja a gép, megfelelő gyorsteszt is kell (ilyen már több is készült),
vagy a Zozotools RL NEW parancsával láncolhatjuk be a programokat. (Pl.: RL
NEW,30h,20h,0Fh,0Ch,07h,06h,04h,03h,02h)
Nézzük a kompatibilitási kérdéseket:
Két áramkörös, kétállású kapcsoló bekötése:
DAVE CART - - U31 3-as láb
cartridge B4 - - cartridge B3
74138 1-es láb - - A17
Az átalakításhoz segítségül néhány csatlakozó kiosztás, és az IC lábkiosztása:
EP BUS |
Cartridge |
|||||
Billentyűzet felöli oldal |
hűtőborda felöli oldal |
|||||
A | B |
A | B |
|||
AUDIO R | 1 |
AUDIO L |
GND | 1 |
+5V |
|
RFSH | 2 |
WR |
D3 | 2 |
D4 |
|
RD | 3 |
IORQ |
D2 | 3 |
??? (U31 3-as láb) |
|
+5V (a gépen üres) | 4 |
+5V (a gépen üres) |
D5 | 4 |
CART |
|
MREQ | 5 |
NMI |
D6 | 5 |
A15 |
|
A8 | 6 |
A9 |
D1 | 6 |
A14 |
|
A10 | 7 |
A11 |
D0 | 7 |
A13 |
|
A12 | 8 |
A13 |
D7 | 8 |
R/W |
|
A14 | 9 |
A15 |
A1 | 9 |
OE |
|
A0 | 10 |
A1 |
A2 | 10 |
A12 |
|
A2 | 11 |
A3 |
A5 | 11 |
A11 |
|
A4 | 12 |
A5 |
A4 | 12 |
A10 |
|
A6 | 13 |
A7 |
A3 | 13 |
A9 |
|
D0 | 14 |
D1 |
A0 | 14 |
A8 |
|
D2 | 15 |
D3 |
A6 | 15 |
A7 |
|
D4 | 16 |
D5 |
GND | 16 |
+5V |
|
D6 | 17 |
D7 |
||||
RESET | 18 |
INT |
||||
WAIT | 19 |
GND |
Felső RAM panel |
|||
MI | 20 |
GND |
EXP2 |
|||
1 Mhz | 21 |
GND |
A | B |
||
CLK | 22 |
GND |
GND | 1 |
+5V |
|
8 Mhz | 23 |
GND |
GND | 2 |
GND |
|
EC0 | 24 |
EC1 |
A21 | 3 |
A20 |
|
EC2 | 25 |
EC3 |
A19 | 4 |
A18 |
|
EXTC | 26 |
A16 |
A17 | 5 |
A16 |
|
A17 | 27 |
A18 |
||||
A19 | 28 |
A20 |
EXP1 |
|||
A21 | 29 |
14 Mhz |
RFSH | 6 |
MREQ |
|
GND | 30 |
VSYNC |
D6 | 7 |
D7 |
|
GND | 31 |
Üres |
D4 | 8 |
D5 |
|
HSYNC | 32 |
GND |
D2 | 9 |
D3 |
|
GND (a gépen +9V!) | 33 |
GND (a gépen +9V!) |
D0 | 10 |
D1 |
|
Innentől már csak a buszbűvítőn vagy hídon |
A6 | 11 |
A7 |
|||
Üres | 34 |
Üres |
A4 | 12 |
A5 |
|
GND | 35 |
+4V |
A2 | 13 |
A3 |
|
GND | 36 |
GND |
A0 | 14 |
A1 |
|
Üres | 37 |
Üres |
A14 | 15 |
A15 |
|
A12 | 16 |
A13 |
||||
A10 | 17 |
A11 |
||||
A8 | 18 |
A9 |
||||
WR | 19 |
RD |
||||
Billentyűzet felöli oldal |
IC-k lábkiosztása
27512 |
62256 |
27256 |
27128 |
![]() |
27128 |
27256 |
62256 |
27512 |
64 Kbyte |
32 Kbyte |
32 Kbyte |
16 Kbyte |
16 Kbyte |
32 Kbyte |
32 Kbyte |
64 Kbyte |
|
A15 |
A14 |
Vpp |
Vpp |
+5 V |
+5 V |
+5 V |
+5 V |
|
A12 |
A12 |
A12 |
A12 |
PGM |
A14 |
R/W |
A14 |
|
A7 |
A7 |
A7 |
A7 |
A13 |
A13 |
A13 |
A13 |
|
A6 |
A6 |
A6 |
A6 |
A8 |
A8 |
A8 |
A8 |
|
A5 |
A5 |
A5 |
A5 |
A9 |
A9 |
A9 |
A9 |
|
A4 |
A4 |
A4 |
A4 |
A11 |
A11 |
A11 |
A11 |
|
A3 |
A3 |
A3 |
A3 |
0E |
0E |
0E |
0E |
|
A2 |
A2 |
A2 |
A2 |
A10 |
A10 |
A10 |
A10 |
|
A1 |
A1 |
A1 |
A1 |
CE |
CE |
CE |
CE |
|
A0 |
A0 |
A0 |
A0 |
D7 |
D7 |
D7 |
D7 |
|
D0 |
D0 |
D0 |
D0 |
D6 |
D6 |
D6 |
D6 |
|
D1 |
D1 |
D1 |
D1 |
D5 |
D5 |
D5 |
D5 |
|
D2 |
D2 |
D2 |
D2 |
D4 |
D4 |
D4 |
D4 |
|
GND |
GND |
GND |
GND |
D3 |
D3 |
D3 |
D3 |
ZozoHard - Enterpress 1993/3
Az Életjáték lassan több évtizede a matematikusok (és nem matematikusok) kedvenc időtöltése. Elegendő hozzá egy kockás papír és egy ceruza, meg némi türelem; persze, igazi reneszánszát a játék a számítógépek elterjedésével éli.
Az Életjáték a sejtautomaták tudományának egy "mellékterméke". A sejtautomaták elmélete egymás mellett elhelyezett sok-sok egyszerű elemből felépülő rendszerekkel foglalkozik. Ezek az elemek az élő szervezet sejtjeihez hasonló elrendezésben töltik ki a síkot vagy a teret, az egyes sejtek csak a közvetlen szomszédjaikkal képesek kommunikálni. A sejtautomaták régóta izgatják a szakemberek fantáziáját, hiszen köztudomású, hogy az emberi agy felépítéséhez ezek sokkal közelebb állnak, mint a jelenleg alkalmazott számítógépek. Elképzelhető, hogy a sejtautomaták segítségével olyan problémák is megoldhatók lesznek, amelyeket eddig a hagyományos számítógépekkel nem, vagy csak nagyon körülményesen lehetett megoldani. Csak példaképpen: bizonyított tény, hogy építhető olyan sejtautomata, amelyik képes önmaga reprodukálására, azaz szaporodásra; ez azt jelenti, hogy rendelkezik az élő szervezet egyik jellemző tulajdonságával. Az önreprodukálásra majd látunk egy egyszerűsített példát.
Az élő szervezetek, különösen pedig az ember másik jellemzője a tanulás és a képzettársítás; ezen a területen a sejtautomaták egyik ága, az úgynevezett neuronhálózatok - az emberi agy szerkezetét és működését utánozni próbáló rendszerek - mutattak fel egyre izgalmasabb eredményeket.
De térjünk vissza az Életjátékhoz! A játéktér egy - elvileg - végtelen kiterjedésű sejttér, amit egy négyzetrácsos (a köznyelvben egyszerűen kockás) papírral modellezünk. A sejttér minden elemének - a játék hagyományos formájában - két állapota lehet: vagy tartalmaz egy élő sejtet, vagy üres. A játék valamilyen - véletlenszerű vagy célzatosan megválasztott - kiinduló konfigurációval indul. A továbbiakban az élő sejtek jól definiált szabályok szerint tovább élnek vagy elpusztulnak; az üres mezőkön pedig új sejtek születhetnek. Mindezekről az határoz, hogy az adott mezővel szomszédos mezők mit tartalmaznak.
Minden mezőnek 8 lehetséges szomszédja van, a négy oldalszomszéd és a négy sarokszomszéd. Az ábrán a körrel jelölt ("lakott") mező nyolc szomszédos mezejét ponttal jelöltük.
A sejtek úgy viselkednek, mint az élő sejtek: egyedül, egymás nélkül elpusztulnak, ugyanakkor a zsúfoltságot sem tudják elviselni, agyonnyomják egymást. Ha viszont kedvező körülmények uralkodnak, az üres mezőben egy új sejt keletkezik.
Az Életjáték eredeti, Conway által kigondolt formájában a születési, meghalási és életbenmaradási szabályok a következők:
Ha egy élő sejtnek nincs szomszédja, vagy csak egy szomszédja van, elpusztul az egyedülléttől. Ha négy vagy több szomszédja van, ugyancsak elpusztul a túlzsúfoltságtól. A túléléshez tehát két vagy három szomszéd szükséges.
Ha egy üres mezőnek pontosan három élő szomszédja van, a mezőben új sejt születik. A sejtek pusztulása és az új sejtek születése az adott konfigurációban egyszerre, "vezényszóra" megy végbe, így a változás nem függ a kiértékelés sorrendjétől.
Az Életjáték azért jelent igazi kihívást a játékos elmének, mert sokszor egészen egyszerű kiinduló alakzatból sok száz vagy sok ezer lépésen keresztül változó, fejlődő sejtközösség alakul ki.
A következő ábrán látható kezdő konfigurációban (három sejt vízszintesen egymás mellett) a két szélső sejtnek csak egy-egy szomszédja van, ezért a következő lépésben ezek elpusztulnak; a középső sejtnek viszont két-két szomszédja van, ezért ez megmarad. Hogy a dolog ne legyen ilyen szomorú, a középső sejt alatti és feletti mezőnek három-három szomszédja van, ezért ebben a két mezőben egy-egy új sejt születik. Eredményül a jobb oldali ábrán látható elrendezést kapjuk (mintha a három sejtből álló alakzat elfordult volna 90 fokkal). Nem nehéz rájönni, hogy a következő lépésben újra visszakapjuk a kiinduló alakzatot, és ez így fog ismétlődni az idők végezetéig. Ez az alakzat az Életjáték egyik nevezetes figurája (a neve villogó), gyakran keletkezik bonyolultabb alakzatok szétesésekor. Az alakzat 2 időegység alatt visszakerül a kiindulási állapotába.
Itt mutatunk még három ábrát (a kockát, a cipót és a vitorlázórepülőt). Javasoljuk, hogy próbálja meg végigkövetni fejlődésüket! Próbáljuk meg az öt és a hét, vízszintesen (vagy függőlegesen) egymás mellett lévő sejt életútját megjósolni!
A kocka és a cipó stabil alakzat, nem változik; a vitorlázórepülő viszont változik, de 4 időegységnyi periódussal ismétli önmagát, miközben átlósan lefelé "siklik" a sejttérben.
Eláruljuk, hogy több hasonló vitorlázórepülő létezik; keressük meg ezeket!
Érdekes probléma, hogy létezik-e olyan alakzat, amelyik mozog, és haladtában gőzmozdonyként füstcsíkot húz maga után. És van-e olyan, amelyik járműként végighalad az úton, azaz egymás mellett sorban elhelyezkedő sejteken? Létezik-e ágyú, amelyik valamilyen mozgó alakzatot képes kilőni magából? Mi történik két mozgó alakzat, például két vitorlázórepülő összeütközésekor?
Mindezekre a kérdésekre csak úgy érdemes választ keresni, ha nem papíron és ceruzával próbálkozunk, hanem elkészítjük a megfelelő programot.
Mielőtt belevetnénk magunkat a programírásba, néhány apró kérdést meg kell vizsgálni. Először, a konfiguráció változásának egyszerre kell végbemennie. Ehhez külön tárolnunk kell az éppen aktuális konfigurációt, valamint a következő lépésben kialakuló helyzetet (vagy legalább annak egy részét).
A másik, hogy egy-egy életrevalóbb konfiguráció könnyen leszalad a képernyőről. A baj nem is igazán az, hogy ilyenkor nem látjuk a túlszaladt részt, hanem az, hogy a képernyő szélén lévő sejteknél esetleg hibásan generáljuk a következő állapotot.
Ennek elkerülésére a tényleges játékteret érdemes nagyobbra választani, mint ami a képernyőn elfér, és külön mechanizmussal figyelni, ha a növekvő sejtkupac mégis elérné a játéktér szélét.
A harmadik probléma előreláthatóan a sebesség lesz; mivel egy elég nagy területen kell a sejtek változását figyelni, félő, hogy a program rendkívül lassú lesz, különösen BASIC-ben. Meg kell próbálni olyan eszközöket felhasználni, amelyekkel a végrehajtás felgyorsítható.
Most lássunk hozzá a programtervezésnek! Mielőtt bárki nekiesne, hogy
10 LET I=1 ...
vagy a mindenre, csak korszerű programozásra nem alkalmas folyamatábrát kezdenénk rajzolni, próbáljunk nagyobb léptékben gondolkodni. A program két nagyobb egységre bontható. Az egyikben mindenféle beállítást végzünk: kezdőértéket adunk a használt változóknak, letöröljük a képernyőt, beállítjuk a kiinduló konfigurációt stb. Nevezzük ezt a részt ELŐKÉSZÍTÉS-nek. A másik programrész a tulajdonképpeni játék, amelyben az újabb és újabb állapotokat generáljuk. Legyen ennek a neve JÁTÉK. Programunk tehát most így néz ki:
ÉLETJÁTÉK:
ELŐKÉSZÍTÉS;
JÁTÉK;
END. (ÉLETJÁTÉK)
Mielőtt bármilyen elhamarkodott következtetést tennénk e két nagyobb egység felépítésére vonatkozóan (tehát mielőtt
100 FOR I=1 TO 24
110 FOR J=1 TO 40
jellegű dolgokat kezdenénk írkálni), gondoljuk át, milyen módon lehet az egymást követő generációkat a gépen ábrázolni! Ehhez nyilván valamiféle táblázatra lesz szükségünk. A feladat megfogalmazásából azonban az is következik, hogy egyetlen táblázat nem elegendő, hiszen az adott elemkonfiguráció csak akkor változhat meg, ha már a teljes jelen konfigurációt kiértékeltük, ellenkező esetben a megoldás módjától függő, hamis eredményt kapnánk.
Kézenfekvő volna egy olyan táblázatot használni, amelynek minden eleme két-két állapotot tárolna: a jelenlegit és a kiértékelés alatti következőt. Sajnos, a BASIC nyelvek többsége, így az IS-BASIC sem engedi meg összetett típusok használatát. Maradna egy háromdimenziós tömb lehetősége, amelyben az első két dimenzió értelemszerűen a sor-és az oszlopkoordináta volna, a harmadik pedig mindössze két értékkel bírna, a jelenlegi és a következő állapot tárolására. Sajnos, a BASIC csak kétdimenziós tömböt enged meg. Summa summárom, bármennyire ellenkezik a józan programozói gondolkodással, marad a két különböző táblázat használata. Ennél most ne is menjünk tovább.
A program pszeudokódja most így néz ki:
ÉLETJÁTÉK:
VAR
TÁBLA-1
TÁBLA-2
BEGIN
ELŐKÉSZÍTÉS;
JÁTÉK;
END.
A program JÁTÉK részéről tudjuk, hogy ismétlődő folyamat:
JÁTÉK:
REPEAT
LÉPÉS
END-REPEAT;
END. (JÁTÉK)
Az ELŐKÉSZÍTÉS részt pedig így bontjuk ki:
ELŐKÉSZÍTÉS:
ALAPHELYZET (TÁBLA-1, TÁBLA-2);
KEZDŐKONFIGURÁCIÓ (TÁBLA-1);
EGYÉB;
END
Önkényesen TÁBLA-1-et választottuk a kezdő konfiguráció számára. A másik alternatíva ugyanilyen jó lett volna; mivel a döntésnek nincs igazán jelentősége, nem töprengünk rajta sokáig (a tett halála az okoskodás).
Most értünk el oda, hogy a táblázatok pontosabb definiálását már nem lehet tovább halasztani. Kézenfekvő, hogy valami ilyesfajta deklarációjuk legyen:
VAR TÁBLA-1, TÁBLA-2 : ARRAY [SOROK, OSZLOPOK] OF ADATELEM;
Egyáltalán nem sietünk viszont meghatározni, mit értünk sorokon és oszlopokon, sem pedig adatelemen.
Ha viszont ismerjük a táblázatok szerkezetét, pontosíthatjuk a JÁTÉK programrész LÉPÉS elemét:
LÉPÉS:
SOROKON-VÉGIG DO
OSZLOPOKON-VÉGIG DO
TEDD-AMIT-KELL;
END-DO;
END-DO:
END (LÉPES)
Tovább nem tudunk menni, mert nem tudjuk, MIT-KELL-TENNI (sic). Előbb valamiféle döntést kell hoznunk az adatok ábrázolásáról. Egy pillanatra megfeledkezve rossz BASIC-es beidegződéseinkről és az azzal járó 0 és 1 vagy hasonló választékról, meghatározzuk a táblázatelemek típusát:
TYPE ADATELEM : (ÉL, NEM-ÉL);
Ennek alapján most már elég részletes megoldást tudunk adni az ALAPHELYZET programrészre:
ALAPHELYZET:
SOROKON-VÉGIG DO
OSZLOPOKON-VÉGIG DO
TÁBLA-1 [SOR, OSZLOP] := NEM-ÉL;
TÁBLA-2 [SOR, OSZLOP] := NEM-ÉL;
END DO
END-DO
END (ALAPHELYZET)
A két táblázatot alaphelyzetbe állíthattuk volna két külön ciklusban is, de intuitív módon gyorsabbnak találtuk ezt a megoldást. A kezdő konfiguráció beállításával most nem törődünk; a program kipróbálásához majd megadunk valami egyszerű elrendezést.
Itt az ideje, hogy komolyan belenézzünk a megoldás részleteibe. Jól tudjuk, hogy egy adott cellában az ott lévő sejt megmaradása vagy elpusztulása, illetve egy üres cellában egy sejt születése vagy nem születése valamilyen módon a cella szomszédaitól, egészen pontosan a szomszédai számától függ. Ez pontosan elegendő információ a folytatáshoz. Definiálunk egy FÜGGVÉNY nevű függvényt, amelynek bemenő paraméterei a szomszédok száma és a cella saját állapota (ÉL vagy NEM-ÉL), a függvényérték pedig ugyanilyen típusú, vagyis azt mondja meg, hogy a következő pillanatban ugyanitt lesz-e sejt vagy nem.
TEDD-AMIT-KELL:
TÁBLAEELEM (MÁSIK-TÁBLA) :=
FÜGGVÉNY (SZOMSZÉDOK, TÁBLAELEM (EGYIK-TÁBLA));
END (TEDD-AMIT-KELL)
Most segítene, ha a táblázatokat értelmesen meg tudtuk volna határozni, így kénytelenek vagyunk egy ostobább megoldást alkalmazni (a "...maga mindent kétszer mond, kétszer mond..." fajtából):
TEDD-AMIT-KELL:
IF MUTATÓ = EGYIK-ÁLLAPOT THEN
TÁBLA-2 [SOR, OSZLOP] := FÜGGVÉNY(SZOMSZÉDOK,TÁBLA-1 [SOR,OSZLOP]);
ELSE
TÁBLA-1 [SOR, OSZLOP] := FÜGGVÉNY(SZOMSZÉDOK,TÁBLA-2 [SOR,OSZLOP]);
END-IF;
END (TEDD-AMIT-KELL)
Ez feltételezi a globális MUTATÓ változó létezését, amellyel sok bajunk lesz: először is deklarálni kell; másodszor kezdőértéket kell kapnia; harmadszor, minden LÉPÉS után másik (nem más!) állapotba kell billentenünk. Ezt adminisztráljuk:
VAR MUTATÓ: (EGYIK-ÁLLAPOT, MÁSIK-ÁLLAPOT);
LÉPÉS:
SOROKON-VÉGIG DO
OSZLOPOKON-VÉGIG DO
TEDD-AMIT-KELL
END-DO
END-DO
INVERTÁL (MUTATÓ);
END (LÉPÉS)
és
ELŐKÉSZÍTÉS:
ALAPHELYZET (TÁBLA-1, TÁBLA-2);
KEZDŐ-KONFIGURÁCIÓ (TÁBLA-1);
MUTATÓ := EGYIK-ÁLLAPOT;
EGYÉB;
END (ELŐKÉSZÍTÉS)
Most már csak SZOMSZÉDOK és a FÜGGVÉNY függvény szorul némi pontosításra. Az Életjátékban az elem négy él- és négy sarokszomszédja számít. Egy pillanatra elcsábulnánk, hogy írjunk egy kettős ciklust, amelyik az elem előtti sortól és oszloptól az utána következő sorig és oszlopig megy, nem felejtve el kihagyni a számításból magát az elemet; de lerázzuk a sematizmus béklyóját, megérezve, hogy a megoldás lassú lenne. (IS-BASIC-ben a kettős ciklus nagyon lassú. Vegyük észre, hogy a LÉPÉS saját két ciklusával együtt négyszeresen skatulyázott ciklusunk volna!) Inkább leírjuk nyolcszor egymás után (a "kétszer mond" effektust figyelembe véve, 16-szor) az indexkifejezést (egy jó szövegszerkesztővel ez nem probléma):
SZOMSZÉDOK (SOR, OSZLOP):
IF MUTATÓ = EGYIK-ÁLLAPOT THEN
RETURN WITH TÁBLA-1 [SOR - 1, OSZLOP - 1]
+ TÁBLA-1 [SOR - 1, OSZLOP] + TÁBLA-1 [SOR - 1, OSZLOP + 1]
+ TÁBLA-1 [SOR, OSZLOP - 1]
{ itt kimarad az elem maga }
+ TÁBLA-1 [SOR, OSZLOP + 1] + TÁBLA-1 [SOR + 1, OSZLOP - 1]
+ TÁBLA-1 [SOR + 1, OSZLOP] + TÁBLA-1 [SOR + 1, OSZLOP + 1]
ELSE
RETURN WITH {ugyanaz, mint az előbb, csak TÁBLA-1 helyett TÁBLA-2 mindenütt}
END-IF
END (SZOMSZÉDOK)FÜGGVÉNY (SZOMSZ, SAJÁTÉRTÉK):
IF SAJÁTÉRTÉK = NEM-ÉL THEN
IF SZOMSZ = 3 THEN
RETURN WITH ÉL
ELSE
RETURN WITH NEM-ÉL
END-IF
ELSE { azaz ha él a sejt }
IF SZOMSZ = 2 OR SZOMSZ = 3 THEN
RETURN WITH ÉL
ELSE
RETURN WITH NEM-ÉL
END-IF
END-IF
END (FÜGGVÉNY)
Már majdnem készen vagyunk, csak azt kell eldöntenünk, hogy mit jelentsen a SOROKON-VÉGIG és az OSZLOPOKON VÉGIG. Mivel a táblázat legszélén a SZOMSZÉDOK függvény nem működik (kilóg a lóláb, akarom mondani, az index az indexhatárból), a LÉPÉS célszerűen a második sortól és oszloptól az utolsó előtti sorig és oszlopig megy majd. Mielőtt elhamarkodnánk, definiálunk néhány konstanst:
CONST
SORSZÁM = 24;
OSZLOPSZÁM = 38;
Első próbálkozásként alkalmazkodunk a megjeleníthető mérethez, nem elhanyagolva keserű tapasztalatunkat, hogy az utolsó két oszlopot az EDITOR "nem szereti", esetleg átviszi kedves sejtjeinket a következő sorba. Később úgyis rájövünk, hogy ez az élettér komolyabb konfiguráció esetén kevés, akkor csak ezt a két konstanst kell majd módosítani. Akkor viszont majd ügyelni kell arra, hogy mi látszik az ábrából.
Erről eszembe jut, hogy jelenleg semmi sem látszik. Kacérkodunk a gondolattal, hogy esetleg egy kettős ciklussal minden LÉPÉS után végigsöprünk az aktuális táblán, és kirajzoljuk a képernyőre a tartalmát. Ez persze rettenetesen lassú lenne. Azután eszünkbe jut, hogy egy-egy lépés során a konfiguráció nem nagyon változhat, hiszen minden sejt csak a közvetlen környezetére gyakorol hatást. Ezért úgy döntünk, hogy mindig csak a változást rajzoljuk, ehhez pedig (bár programozói énünk - helyesen - berzenkedik ellene) a rajzolást becsempésszük a FÜGGVÉNY függvénybe (ott ugyanis mindig tudjuk, van-e változás). Emiatt a FÜGGVÉNY paraméterei kibővülnek a sor- és az oszlopkoordinátával.
Ha az ELŐKÉSZÍTÉS eljárás KEZDŐKONFIGURÁCIÓ részébe beleügyeskedünk egy egyszerű kezdő ábrát, nem feledkezve meg annak kirajzolásáról sem, akkor egy Pascal-szerű nyelvet használva szinte változtatás nélkül indíthatnánk a programot; ha beziklábasan (bocsánat, BASIC-ben) dolgozunk, akkor viszont egy kevés kódolási munkával az alábbi programhoz jutunk:
100 PROGRAM "Lifegame.bas"
110 LET SORSZ=23:LET OSZLSZ=38
120 NUMERIC E(1 TO 23,1 TO 38)
130 NUMERIC F(1 TO 23,1 TO 38)
140 NUMERIC SOR1,SOR2,OSZL1,OSZL2,Q
150 LET SOR1=1:LET SOR2=SORSZ:LET OSZL1=1:LET OSZL2=OSZLSZ:LET Q=1
160 DEF KEZD
170 FOR II=1 TO SORSZ
180 FOR JJ=1 TO OSZLSZ
190 LET E(II,JJ),F(II,JJ)=0
200 NEXT JJ
210 NEXT II
220 LET E(2,4),E(3,2),E(3,4),E(4,3),E(4,4)=1
230 PRINT AT 2,4:"*"
240 PRINT " * *"
250 PRINT " **"
260 END DEF
270 DEF SZOMSZ(S,O)
280 IF Q>0 THEN
290 LET SZOMSZ=(E(S-1,O-1)+E(S-1,O)+E(S-1,O+1)+E(S,O-1)+E(S,O+1)+E(S+1,O-1)+E(S+1,O)+E(S+1,O+1))
300 ELSE
310 LET SZOMSZ=(F(S-1,O-1)+F(S-1,O)+F(S-1,O+1)+F(S,O-1)+F(S,O+1)+F(S+1,O-1)+F(S+1,O)+F(S+1,O+1))
320 END IF
330 END DEF
340 DEF FUGGV(SZ,P,K,L)
350 IF P=0 THEN
360 IF SZ=3 THEN
370 LET FUGGV=1
380 PRINT AT K,L:"*";
390 ELSE
400 LET FUGGV=0
410 END IF
420 ELSE
430 IF SZ<2 OR SZ>3 THEN
440 LET FUGGV=0
450 PRINT AT K,L:" ";
460 ELSE
470 LET FUGGV=1
480 END IF
490 END IF
500 END DEF
510 DEF LEP
520 NUMERIC I,J
530 FOR I=1+1 TO SORSZ-1
540 FOR J=1+1 TO OSZLSZ-1
550 IF Q>0 THEN
560 LET F(I,J)=FUGGV(SZOMSZ(I,J),E(I,J),I,J)
570 ELSE
580 LET E(I,J)=FUGGV(SZOMSZ(I,J),F(I,J),I,J)
590 END IF
600 NEXT J
610 NEXT I
620 END DEF
630 TEXT 40
640 CALL KEZD
650 DO
660 CALL LEP
670 LET Q=-Q
680 LOOP
Ne indítsuk el! Borzalmasan lassú lesz. Az előkészítés mintegy fél percig megy - ezt még kibírnánk - viszont egy-egy generáció generálása (sic) két és fél percig tart, ami tarthatatlan (sic). Az egyetlen gyors megoldás, ha a programot azonmód lefordítjuk a ZZZZZZZZZZZZIP-el (itt egy kicsit megszaladtak a Z betűk, elég lesz belőlük három is). (Ez megmagyarázza a lokális változók suta megválasztását: a ZZZIP nem fogad el azonos nevű változókat. A ZZZIP által ránk erőszakolt megkötések nélkül egyébként még egyszerűbben és szebben meg lehetett volna csinálni a programot.)
Így már elfogadható a sebesség, de még nem mondtuk ki az utolsó szót. Akinek kedve van, megpróbálhatja gyorsítani azt. Természetesen nem bitfaragásra gondolunk, hanem az algoritmus javítására.
Egy optimalizálást már "elkövettünk" menet közben: nem hagytuk magunkat rábeszélni a teljes képmező újrarajzolására. Enélkül a program csak elméleti érdekességgel bírna, használni nem lehetne. Ezzel étjük el egyébként a legnagyobb javulást a sebességben, és nemcsak BASIC-ben, hanem más, gyorsabb programnyelveken is.
Egy további lehetőség a SZOMSZÉDOK függvény optimalizálása: a megoldás jelenleg nem vesz tudomást arról, hogy a kiszámolandó összeg egy része az előző cellánál kiszámolt összegben már "benne van". Kérdés, hogy ezzel lehet-e időt megtakarítani.
Egy másik (nagyon hatásos) beavatkozás, ha nem "faltól-falig" megyünk, hiszen az ábra általában csak a sejttérnek egy kis részét foglalja el. Itt azt lehet kihasználni, hogy az ábra alsó és felső, illetve bal és jobb szélső eleme minden lépésben legfeljebb egy mezőnyivel terjeszkedhet. Elegendő tehát egy minden lépésben újra meghatározandó korlátpár-pár között vizsgálni a táblázatot.
Természetesen csak akkor jutunk használható programhoz, ha megoldjuk a kiinduló konfiguráció berajzolását. Nem árt figyelni, hogy a sejthalmaz nem terjed-e túl a rendelkezésre álló területen. (Ilyenkor továbbmenve hamis eredményt kapunk.) Ha pedig az optimalizálást túlzásba vittük, nem árt a lépésenkénti végrehajtásra felkészülni, hogy egyáltalán lássunk is valamit. (Bár, lehet, hogy ez még odébb van...)
Ha eluntuk az Életjátékot, a SZOMSZÉDOK és a FÜGGVÉNY függvény átírásával egyéb sejtszimulációt is előállíthatunk. Nagyon érdekes pl. az az eset, amikor csak az élszomszédokat vesszük figyelembe, és a szám paritását vizsgáljuk (páros számú szomszéd esetén lesz sejt a cellában, páratlan számúnál nem lesz). Ilyenkor a sejtalakzat néhány lépésben megnégyszerezi önmagát. ("Kész az önreprodukáló sejtautomata!" - kiáltunk fel, de korai az öröm, a szakemberek szerint ez nem az!).
"A mű kész, az alkotó pihen" - mondta egy fehér szakállú programozó, amikor egy kicsit más jellegű életjátéka végre úgy-ahogy elindult (a program azóta sem hibátlan, pedig alkotója már minimum a 6.2 verziónál tart vele). Csak azt akartuk megmutatni, hogy átgondolt, korszerű programtervezési módszerrel nem kell hat nap egy ekkora program létrehozásához. Körülbelül egy órai munkával (az eszközök: papír, ceruza, fej) és tízegynéhány percnyi begépeléssel azonnal működő, toldozást-foldozást nem igénylő program készíthető.
Ujlaki László
Az IS-Basic SET CHARACTER parancsával a gép karakterképeit könnyedén megváltoztathatjuk. A kezdők számán azonban bonyolultnak tűnik a szükséges jellemzők meghatározása, a karakterek tervezése. Nekik szántuk az alábbi írást.
Mint a számítógépben minden, így a karakterképek szerkesztése is a kettes számrendszerhez kapcsolódik. Az egyes karakterek 8 bit szélesek, és 9 bit magasak, a teljes karaktert tehát 72 bit íja le. Tudjuk, hogy a bit tulajdonképpen egy kétállapotú kapcsoló, amely ha be van kapcsolva, akkor értéke egy, egyébként pedig nulla. Ha a kapcsolóállapotot levetítjük a karakterekre, akkor azt mondhatjuk, hogy a bekapcsolt bit látszik, a kikapcsolt nem.
A karakter - tervezés szempontjából - 8 egység széles, 9 egység magas mátrixként fogható fel. A karaktert ebben a mátrixban kell megrajzolni (célszerű kockás papírt használni). Nem véletlen, hogy 8 egységből, azaz 8 bitből áll össze a karakter egy-egy sora: ezt bájtként lehet értelmezi, a gép ekként is kezeli A bájtban tehát 8 bit foglal helyet, minden bitnek helyértéke van.
A karakter egyes sorai bájtokat takarnak, 9 ilyen bájt van egymásra helyezve a karakterben. A bájt jobb szélső bitje a 0., a bal szélső a 7. sorszámot viseli. Mivel a bit két állapotot vehet fel, így a 0. bit helyértéke 2^0=1, az 1. bité 2^1=2, a 2. bité 2^2=4 és ígytovább egészen 2^7=128-ig, ezek az értékek láthatók az ábra alján. A sorokat alkotó bájtok értékeit egyszerűen úgy kell meghatározni, hogy összeadjuk az azon bitekhez tartozó helyértékeket, ahol a bit értéke egy. A melléklet ábra legfelső sorának értéke így 16+8=24, hiszen a negyedik és a harmadik bit van egybe állítva. Ezt az eljárást követve mind a kilenc sornál elvégezzük a számítást. Ha elkészültünk ezzel, akkor a kapott számokat közölnünk kell a géppel, ezt a SET CHARACTER paranccsal tehetjük meg. A parancs első paramétere az az ASCII kód, amelyhez tartozó karakter képét át kívánjuk definiálni. Az ezt követő kilenc paraméter a karaktert alkotó kilenc értéket jelenti, elsőnek a karakter tetején állót kell megadni. Az utasítás formája tehát
Az ábrázott karaktert tegyük az "A" betű helyére, ennek ASCII kódja a 65.
Bizonyára sokan furcsálják, hogy miért nekünk kell ezeket az értékeket kiszámítani, miért nem bízzuk ezt a gépre? Nekik teljesen igazuk van, hiszen: "Dolgozzanak a gépek, gondolkozzanak az emberek". A BASIC rendelkezik a BIN() függvénnyel, amellyel az egyes sorok értékei kiszámíthatók. A függvény felhasználására láthatunk példát a következő programlistán: |
![]() |
100 PROGRAM "CharDef.bas"
110 NUMERIC C(1 TO 9)
120 LET C(1)=BIN(0011000)
130 LET C(2)=BIN(0100100)
140 LET C(3)=BIN(1000010)
150 LET C(4)=BIN(1000010)
160 LET C(5)=BIN(1111110)
170 LET C(6)=BIN(1000010)
180 LET C(7)=BIN(0)
190 LET C(8)=BIN(0)
200 LET C(9)=BIN(0)
210 SET CHARACTER ORD("A"),C(1),C(2),C(3),C(4),C(5),C(6),C(7),C(8),C(9)
Az Enterprise-Plus BASIC-bővítés még egyszerűbbé teszi a karakterek átdefiniálását. Erre két utasítás szolgál: Az CHRDEF egy adott karakter definiálásának kezdetét jelzi. Ezután kilenc, nem feltétlenül egymást követő CHRLIN utasítás kell, hogy kövesse. A CHRLIN utasítás a karakter egy-egy sorát adja meg: ebben a szóköz hatására a megfelelő bit törlődik, "." (pont) hatására megmarad az eredeti karakter pontja, minden más karakter pedig egybe állítja a bitet.
100 PROGRAM "CharDef.bas"
120 CHRDEF "A"
130 CHRLIN " xx "
140 CHRLIN " x x "
150 CHRLIN " x x "
160 CHRLIN " xxxxxx "
170 CHRLIN " x x "
180 CHRLIN " x x "
190 CHRLIN " "
200 CHRLIN " "
210 CHRLIN " "
BASIC programok
láncolása
Az Enterprise memóriájában több programot is tárolhatunk egyidőben. Az egyes
programokat 0 és 127 közé eső sorszámmal különböztetjük meg egymástól. A nullás
számú program számára legfeljebb 42K, minden további számára legfeljebb 32K
helyet biztosít a BASIC rendszer. Az EDIT <sorszám>, vagy EDIT<név>
paranccsal határozzuk meg, hogy éppen melyik programot akarjuk szerkeszteni.
Ennek számát a gép a képernyő felső részén ki is írja. Az éppen szerkesztett
programot a sima SAVE és LOAD parancsokkal tudjuk elmenteni és betölteni, illetve
a NEW-val törölni. (Ha valaki nem tudná: ha a program elején a PROGRAM "név"
utasítást használjuk, akkor a SAVE után nem kell kiírni a nevet, mert tudja.)
Ha az összes programot csoportosan akarjuk kezelni: a SAVE ALL parancs az összes
programot az első neve alatt tárolja, a LOAD parancs az így tárolt programokat
egyben visszatölti, a NEW ALL parancs pedig az összes, memóriában lévő programot
törli.
Lehetőség van rá, hogy az egyes programok egymást indítsák, így láncot tudunk
létrehozni. Az utasítás formája:
CHAIN <sorszám> (paraméterek)
vagy:
CHAIN <név> (paraméterek)
Paramétereket csak akkor kell adni, ha a másik programnak adatokat akarunk átadni.
A láncolásra a legegyszerűbb példa:
0. PROGRAM:
10 CHAIN 11. PROGRAM:
10 PRINT "Hello!"
Ha a 0. programot elindítjuk, azonnal meghívja az egyes számút,
amely végrehajtja a PRINT utasítást. Amikor a futás befejeződik, az egyes program
területén maradunk (lásd a számot a képernyő tetején).
Az alábbi példában a paraméterátadást figyeljük meg:
0. PROGRAM:
10 PROGRAM "nulla"(a,b,c)
20 PRINT "Nulladik progi"
30 PRINT a,b,c
40 CHAIN 1 (1,2,3)1. PROGRAM:
10 PROGRAM "egy"(a,b,c)
20 PRINT "Egyes progi"
30 PRINT a,b,c
40 CHAIN 0
Mivel a két program kölcsönösen indítja egymást, végtelen ciklust kapunk, és
a képernyőn, amíg a STOP billentyűvel le nem állítjuk, az alábbi feliratok fognak
futni:
Nulladik progi
0 0 0
Egyes progi
1 2 3
Magyarázat: az egyes programot a=1, b=2 és c=3 paraméterekkel hívtuk meg, az
ő számára tehát a, b és c értéke ennyi. A nulladik programot paraméterek nélkül
hívtuk meg, ezért az ő számára az a, b és c változók értéke nulla. Ha most az
egyes program 40. sorába paramétereket is írunk, pl:
40 CHAIN 0 (4,5,6)
akkor ezt kapjuk:
Nulladik progi
0 0 0
Egyes progi
1 2 3
Nulladik progi
4 5 6
Egyes progi
1 2 3
Nulladik progi
4 5 6
Egyes progi
1 2 3
és így tovább.
Az első indításkor a nulladik program paramétereinek még nincs
értéke, amikor azonban az egyes program hívja meg, már van.
A CHAIN hatására a meghívott program mindig az elejétől indul! Ezért sajnos "szubrutinként" nem használhatunk egy másik programot, mert annak
végrehajtása után, ha visszaadjuk a vezérlést a főprogramnak, az újra elölről
fog indulni, és nem a CHAIN utasítás utáni sortól. Ha azonban a nulladik program
pl. csak egy menüt ír ki, akkor már lehetőségünk van a tárban lévő programok
közül aszerint meghívni egyiket vagy másikat, hogy a kezelő melyik menüpontot
választotta. (Kiváló példa erre a Reversi,
Dáma, Awari című játékprogram.)
Ha a hívott programot nem az elejétől szeretnénk indítani, megtehetjük, hogy
paraméterként adjuk át annak a sornak a számát, vagy eljárásnak a nevét, ahonnan
a meghívott programot futtatni kell. Például:
0. PROGRAM:
1. PROGRAM:
10 CHAIN 1("puff')
10 PROGRAM "egyes"(A$)
20 SELECT CASE A$
30 CASE "piff"
40 CALL PIFF
50 CASE "paff"
60 CALL PAFF
70 CASE "puff"
80 CALL PUFF
90 END SELECT
Nevet azért jobb paraméterként átadni, mint sorszámot, mert ha az egyes program szerkezetén változtatunk, és a sorszámok megváltoznak, arról a nullásnak nem kell tudnia. Megjegyzendő, hogy az egyes program indulásakor a változók mindenképpen törlődnek (ahogy egy normál RUN, vagy START után is), egy esetleges előző futásból tehát semmi nem őrződik meg.
Szalontai Andrea - Enterpress 1994/2.
Táblázatos Adatbevitel BASIC-ben
A mellékelt program táblázatos adatbevitelt valósít meg BASIC nyelven, struktúráit stílusban. A beolvasó eljárás (a kiíró blokkal együtt) önállóan is használható. Paraméterei: a beolvasás koordinátái a képernyőn, a beolvasott sztring maximális megengedett hossza és kezdeti értéke. Az eljárás lehetővé teszi a kurzor mozgatását, beszúrást a kurzor pozíciójában, és törlést mindkét irányba, miközben nem engedi meg a felhasználónak, hogy vezérlőkarakterekkel kilépjen a sorból, vagy a megengedettnél hosszabb sztringet vigyen be, amivel elrontaná a képernyőt. Nem megengedett billentyű leütésekor hangjelzést ad. Az eljárás egyszerűen a karakterláncok szétvágásával és újra összeragasztásával dolgozik. Mivel egy karakterhelyre nem lehet egyszerre kiírni egy betűt és a kurzort is, a szövegen belül mozgó kurzor a szöveget kettévágja. Kurzorkarakternek választhatunk más jelet is, pl. egy aláhúzást, ami nem annyira zavaró. Akárhol nyomjuk le az ENTER-t, az eljárás a teljes sztringet beolvassa, miután először kiszedi belőle a kurzorkaraktert. A kiíró eljárás mindig felülírja a szöveget, ezért a gépet ne felejtsük beszúrás üzemmódban, mert elrontja a képet! A T$ változó célja a szöveg törlése az újraírás előtt, ennek hossza szükség szerint változtatható.
A főprogram ennek az eljárásnak a segítségével két szöveg- és egy számtáblázat adatit olvassa be. Mivel a táblázatok hosszúak, egy képernyőoldalra nem férnek ki, ezért lapozni kell őket. A program fő változói:
A képernyőt a KEPERNYO eljárás rajzolja fel. A 106. sorban az elemek sorszámának kiírása természetesen elhagyható, ha nincs elég helyünk. A főcímben úgyis benne van. Figyeljük meg a 105. sorban található feltételt, amely arra szolgál, hogy az utolsó oldalon, amely nincs teljesen tele, magakadályozza, hogy kimenjünk a táblázatból (UBOUND változó!). Hasonló feltétel szerepel a kurzorvezérlő eljárásban is, a lefelé léptetésnél (158. sor).
Amikor megválasztjuk, hogy a táblázatokból hány sort teszünk egy oldalra, hagyjunk helyet az alábbiaknak: felül a főcím, plusz egy sorkihagyás; itt ugyan nem szerepel, de ha az egyes oszlopoknak saját fejlécet akarunk kiírni, akkor az plusz egy sor és egy kihagyás; valamint alul két státuszsor és fölötte egy sorkihagyás. Marad tehát a táblázatra maximum 17 sorunk.
A programnak van egy érdekessége. Mivel a képernyő kiírása lassú, a felhasználónak lehetőséget kell adni arra, hogy még mielőtt egy lap teljesen kiíródik, továbbmenjen a következőre. A képernyőkiíró eljárás minden elemsor után megvizsgálja, hogy a kiírást megkísérelték-e megszakítani. Ha volt billentyűlenyomás, megnézi, hogy mi volt az? A kiírást megszakítani ugyanis csak a lefelé és felfelé lapozó billentyűkkel engedi, és azokkal is csak akkor, ha ez nem okozna hibát (lásd a feltételeket a 113-114. sorokban). Ha ezt nem vizsgálnánk itt meg, a főprogram kerülne végtelen hangjelzést adó hibaciklusba, mivel az újbóli lapozást a főprogrammal végeztetjük el! (Lásd 133-137. sorok, ha a képernyőkiíró ciklus a HIBA változóval azt üzente, hogy már van parancsbillentyű lenyomva, akkor a főprogram nem áll neki újra billentyűre várni, hanem azt vizsgálja meg, ami már benne van az x$ változóban, és mivel az egy lapozó parancs, az OFFSET beállítása után újra meghívja a képernyőkiíró eljárást.) Figyeljük meg azt is, hogy a biztonság kedvéért először csak a FOR ciklusból ugrunk ki, és csak utána a DEF blokkból. (Az ember sose tudhatja, mitől vadul meg a gépe, nem árt óvatosnak lenni. Így legalább a kurzor-koordinátáknak is mindig van értelmes értéke.)
A főprogram a 187-200. sorokban határozza meg, hogy a beolvasó eljárásnak melyik táblázat hányadik elemét kell átadnia. Itt is figyelemre méltó a KEZD, OFFSET és SORSZAM változók használata, valamint az, hogy a beolvasandó elemet referencia-paraméterként adjuk át (lásd a REF kulcsszót a beolvasó eljárás fejlécében). Ez azt jelenti, hogy az eljárás megváltoztathatja az elem tartalmát.
A program végén a teljesség kedvéért bemutatom, hogyan lehet a kész táblázat adatait lemezre, vagy magnóra menteni. A 214. sorban az adatok törlése csak arra való, hogy meggyőződhessünk róla: a program valóban a lemezről olvasta vissza az adatokat és nem a memóriában maradtakat írja ki újra.
A program természetesen szabadon átsorszámozható, saját programjainkba beilleszthető (MERGE), és módosítható is. A főprogram inicializáló részében deklarált változóknak globálisaknak kell lenniük!
Szalontai Andrea - Enterpress 1995/3-4.
Microsoft BASIC programok futtatása Ep-n
Mostani cikkünk tárgya a Golden Baton ismertetőjének egyik félmondata, nevezetesen: "A korabeli BASIC nyelvű játékok.". Először is azt érdemes körüljárni, mit értünk "korabelinek"? Az első otthoni felhasználásra szánt (megfizethető) számítógépek 1977-ben jelentek meg pár hónap eltéréssel: az Apple II (június), TRS-80 Model I (augusztus), és a Commodore PET (október). Ezek közül a TRS-80 számítógépek futották be a legnagyobb "karriert", elsősorban 600 dolláros kezdőárának köszönhetően (szemben az Apple II 1298 dolláros árával). Az előbbi árak természetesen csak a 4 KB-os kiszerelésre értendőek (monitorral), később a 16K-s változatok terjedtek el. A három gép paraméterei teljesen eltérőek voltak, eltérő processzorok dolgoztak bennük, egy valamiben azonban nagyon is hasonlítottak: mindháromban (a TRS-80 gépcsaládban 1978-tól) a Microsoft BASIC valamely változata működött, akárcsak később - igaz csonkítva(!) - a VIC20-ban és C64-ben is, illetve még később - bővítve - Plus-4-en. A TRS-80 Model II számítógépet közvetve mi magyarok is jól ismerhetjük: a magyar gyártású HT-1080Z iskolaszámítógép ennek - kicsit megkésett (1983-as (!)) - klónja.
Mindhárom gép erősen korlátozott grafikai képességekkel bírt, így pont alkalmasak voltak a korábban nagyszámítógépeken készült BASIC-játékok futtatására. Emellett kézenfekvőnek tűnt - Az Adventure sikerén felbuzdulva - szöveges kalandjátékokkal enyhíteni a játszani vágyó amatőrök programéhségét. Amellett, hogy sok szöveges BASIC játék került kereskedelmi forgalomba (mai szemmel nézve megdöbbentő árakon) újságok, könyvek is közöltek - emberfeletti munkával - begépelhető játékokat. A leggrandiózusabb ilyen jellegű könyv talán az 1985-ben a Virgin Books kiadásában megjelent Castles & Kingdoms című könyv, amely 15 begépelhető szöveges kalandjátékot tartalmaz C64-re. Talán nem nehéz belátni, hogy a 15 játék megoldásánál lényegesen nagyobb kihívást jelenthetett azok (hibamentes) begépelése: a közismerten olvashatatlan Microsoft BASIC programlisták - a magyarázatokkal és "körítéssel" együtt 178 oldalt töltöttek meg. (Valószínűleg olcsóbb lett volna a programokat lemezen kiadni, és a vevő is jobban járt volna.). Emellett több könyv is megjelent kimondottan szöveges kalandjátékok írásának mikéntjéről. Ebből mi magyarok is kaphattunk ízelítőt - és többen kedvet -, amikor Frank DaCosta, 1982-es Writing BASIC Adventure program for the TRS-80 című könyve 1986-ban(!) magyar fordításban is megjelent A kalandprogram írásának rejtelmei címmel. Mint az az eredeti címből is látszik a könyv TRS-80-hoz készült, de tökéletesen használható volt HT-1080Z-hez is. Ennek első példaprogramja volt az idehaza nagy karriert befutott Kardhalak és Kincsek program, melynek több, a hazai piacon fellelhető gépre készült, többé - de inkább kevésbé működő maszek verziója (Ep-re már van működő változat!). A könyv magyarországi megjelenése egybeesik hazánkban a szöveges kalandjátékok írásának afféle kisebbfajta "népmozgalommá" válásának kezdeteivel, amiből sajnos a Spectrum kimaradt.
Nem úgy a második iskolaszámítógép, azaz a Plus-4! Tihor Miklós első kalandjátékai a Sárkányölő, a Gengszter még C64-re készültek, ez utóbbi a Commodore Egyesületi lap 1986/4. számában jelent meg, begépelhető formában. A Hős lovag lett az első kereskedelmi forgalomba került magyar nyelvű kalandjáték: C16-ra jelent meg a Novotrade kiadásában (250 Forintért). A játék egy 1980-ban megjelent, eredetileg TRS-80 játék, a Dragonquest alapján készülhetett. (A Castles & Kingdoms című könyvben jelent meg C64 változat belőle, megerősítendő, hogy a C64-es szöveges BASIC kalandjátékok jelentős része még a nagy elődökön készült.) Ezen korai kalandjátékok általános jellemzője - a szűkös (jellemzően 16K, de vannak alapkiépítésű VIC20-ra készült 3,5K-s kalandjátékok is.) memóriakapacitásra tekintettel, hogy nem túl bőbeszédűek, mondhatni "távirati stílusban" kommunikálnak a játékossal. Mindazonáltal lenyűgöző, milyen ötletes játékokat tudtak írni alig 16K-ban, egészen "elvetemült" programozási stílusban... Az eleve C64-re készült kalandjátékok már valamivel közlékenyebbek, pl. Olessák Róbert első - még BASIC-ben készült - kalandjátéka, a Brekk! - Avagy a békává varázsolt királylány.
Ezzel a bevezetővel el is értünk a mostani írás témájához: a Microsoft BASIC változatainak és az IS-BASIC összehasonlítása, hogyan is lehetne az említett játékokat futtatni Ep-n? Azt a felhasználói kézikönyvből tudjuk, hogy "Az Enterprise legtöbbször az ANSI X3J2/82-17 Draft Proposal for Standard BASIC-nak megfelelően jár el." (akármit is jelentsen ez), a futtatni kívánt szöveges kalandjátékok lehetőségei pedig alig mutatnak túl a Minimal BASIC-en. Vegyük sorra az eltéréseket, mit kell módosítani, ha már pl. CBM prg Studio programmal szöveges állományba tudtuk menteni az eredeti programlistát!
Szintaxis
A Microsoft BASIC "leglátványosabb" tulajdonsága, hogy az egyes nyelvi elemek között álló szóköz elválasztó karakter(ek) elhagyható(k). A legtöbb programban el is hagyták a byte-spórolás jegyében (ez a program olvashatóságát persze nagymértékben rontja).
C64-en a legutolsó programsor sorszáma max. 63999 lehet, Ep-n 9999. C64-en RENUMBER nincs, a CBM prg Studio-ban viszont van.
Egy programsor IS-BASIC-ben 254 karakter hosszú lehet, C64-en 80 karakter. Ez több helyen a program egyszerűsítését teszi lehetővé. C64-en ha a THEN után több utasítás áll(na), ami már nem fér bele a 80 karakterbe, kényszerűségből egymás után ugyanazt a feltételt vizsgálva végzik el a műveleteket (vagy GOTO-t használnak), a 80 karakternél többet tároló szöveges változók is csak több sorban kaphatnak értéket (összefűzéssel), ezek mind összevonhatók, akárcsak a rövidebb DATA sorok.
A közhiedelemmel ellentétben Ep-n is egy programsorban több utasítást is írhatunk, kivéve a blokkszervező utasításokat (FOR - NEXT, DO - LOOP, DEF - END DEF, WHEN - END WHEN, HANDLER - END HANDLER), valamint a NUMERIC, STRING, CONTINUE, IMAGE, ON GOTO, ON GOSUB, REM, END utasításokat, melyek minden esetben külön sorban írandók! Figyelni kell még a GOSUB használatára: ez minden esetben a sor utolsó utasítása legyen, mert az ezután lévő utasításokat már nem hajtja végre az interpreter!
Némi hajhullásra adhat még okot a Microsoft BASIC-ben "közkedvelt" IF ... THEN NEXT: A=A+1 típusú szerkezet, ahol a feltétel teljesülése esetén a NEXT hajtódik végre, egyéb esetben a kettőspont után álló további utasítás(ok).
Változók
A Microsoft BASIC-ben a változók neveinek első karaktere csak betű lehet (A-Z), ezt tetszőleges számú alfanumerikus karakter követheti (0-9, A-Z), de csak az első két karakter szignifikáns. A változónév nem tartalmazhat BASIC alapszót (pl. a VALI, WORD nem megengedett). A változó nevekkel tehát nem lesz sok gondunk IS-BASIC-ben bármi jó, ami Microsoft BASIC-ben jó, mindössze az egész típusú változókat jelölő % jelet kell a végéről kivenni.
Nagyobb gond, hogy míg Microsoft BASIC-ben megengedett, hogy egy numerikus változó és egy tömbváltozó ugyanazt a nevet viselje, az IS-BASIC-ben nem. Márpedig úgy tűnik a korabeli programozók ebből sportot csináltak, rendszeresen találkozhatunk READ O(O) típusú - amúgy nagyon csúnya - értékadásokkal. Itt értelemszerűen az egyik változót át kell nevezni.
Anno, akik más gépeken kezdték az ismerkedést a BASIC nyelvvel, rendszeresen szidták az IS-BASIC-et, amiért a változókat - nagyon helyesen - első használat előtt deklarálni kell. Microsoft BASIC-ben nem kell, egy újonnan bevezetett változó automatikusan 0 értéket vagy üres stringet vesz fel. Sőt, a maximum 10 elemű tömbök deklarálása is elhagyható! Ezt ki is használták a programkészítők, a 0 kezdőértékkel rendelkező változók - a memóriaspórolás okán - következetesen nincsenek deklarálva. Talán meglepő, de a Microsoft BASIC ezen "szolgáltatása" felderíthetetlen és így igen gyakori hibát okoz a játékokban. A C64-es kalandjátékok legalább fele(!) tartalmaz a játékmenetet befolyásoló hibát. Ha a program egy esemény megtörténtét pl. O(30)=1000 feltétellel vizsgálná, de helyette O(30)=l000 került a programba, az adott esemény sosem fog bekövetkezni (mert az L000 változó értéke mindig 0 lesz). Ez néhány esetben nem a megoldás egyszerűsödését okozza, hanem épp ellenkezőleg, a játék teljesíthetetlen lesz. Hogy az ilyen hiba mennyire felderíthetetlen, jól példázza, hogy 'A Hős lovag' úgy került kereskedelmi forgalomba, hogy megoldhatatlan. Az ilyen hibákat az IS-BASIC szerencsére jelzi.
Kevesen tudják talán, hogy IS-BASIC-ben az értékadások összevonhatók, egyetlen LET utasítással egyszerre több változónak is adhatunk értéket: LET, A,B,C,D=0.
Szövegfüzérek
Microsoft BASIC-ben a stringek végét jelző idézőjel elhagyható, IS-BASIC-ben nem.
Microsoft BASIC-ben egy szöveges változó maximum 255 karaktert tárolhat. Ep-n 254-et, ha azt a STRING utasítással deklaráljuk, egyébként max. 132 karaktert. Ez nem szokott gondot jelenteni, mert ilyen hosszú sort Microsoft BASIC-ben nem lehet beírni. Szöveges tömbváltozóknál gond lehet viszont a mérettel, mert a Microsoft BASIC másként tárolja a szövegfüzér típusú változókat: a változóterületen csak a string hosszát és egy mutatót tárol. A szövegfüzért a program után a string-területen (a memória végétől lefele terjeszkedve) tárolja úgy, hogy a szövegfüzér-változó helyfoglalása ténylegesen a tárolt karakterek számától függ. Ez a módszer egyrészt nagyon gazdaságosan bánik a memóriával, ha Ep-n ugyanúgy DIM utasítással deklarálnánk egy nagyobb méretű tömböt (mert sok helyszín van a játékban), betelt a memória hibaüzenet kapunk. A STRING utasítást kell használnunk, megadva a maximális hosszt. Másrészt - könnyű belátni - hogy a Microsoft-féle megoldás elképesztően lassítja a szövegfüzér műveleteket: egy 168 szót tároló tömbben a lineáris keresés 14 másodperc C64-en, Ep-n 2 másodperc.
Logikai kifejezések
Az AND művelet természetesen számokra is értelmezhető, de ilyen esetben a Microsoft BASIC-ben a művelet mindig bitenként hajtódik végre. Vagyis a
IF (A AND 47)<>N THEN ...
kifejezés javítandó:
IF (A BAND 47)<>N THEN ...
A szövegfüzéreken értelmezhető műveletek
C64-en a konkatenáció (összekapcsolás) jele a "+", Ep-n "&".
Az általunk ORD néven ismert függvényt (a megadott string-kifejezés első karakterének ASCII kódját adja) a Microsoft BASIC-ben ASC-nek hívják.
A részstring-képzés Ep-n túl logikus és egyszerű, a Microsoft ehelyett rögtön 3 függvényt is bevezetett ugyanerre:
LEFT$(<string>,<aritmetikai kif.>)
A string-ből az első <kif.> számú karaktert adja.
RIGHT$(<string>,<aritmetikai kif.>)
A string végéről <kif.> számú karaktert ad.
MID$(<string>,<kif1>, <kif2>)
A string <kif1> karakterétől <kif2> számú karaktert ad. <kif2> elhagyható, ebben az esetben a string végéig másolja a karaktereket. Úgy tűnik elég nagy zavar lehetett a fejekben e három függvénnyel kapcsolatban, senki ne csodálkozzon, ha pl. MID$(x$,LEN(x$)-N+1) típusú produkciót lát, ez magyarra lefordítva RIGHT(X$,N).
DATA sorok
Microsoft BASIC-ben a DATA sorokban álló szövegfüzéreket csak akkor kell idézőjelbe tenni, ha vesszőt tartalmaznak. Ezzel szemben IS-BASIC-ben akkor is, ha felkiáltójelet is tartalmaz (mert a '!' a megjegyzés jele is).
Microsoft BASIC-ben bájt spórolás célzattal a DATA sorok adatlistáiban a 0 értékeket nem kell kiírni. Vagyis a
DATA 0,1,2,0,0,0,3,4,5,0
és a
DATA ,1,2,,,,3,4,5,
ugyanazt az adatlistát jelenti. IS-BASIC-ben az adatlista utolsó elemét viszont mindenképen ki kell írni, vagyis:
DATA ,1,2,,,,3,4,5,0
Függvények
A C64 BASIC-ben is van POS függvény, de teljesen mást jelent, mint az IS-BASIC-ben: kiszámítja a kurzor helyzetét az aktuális képernyő sorban. A lehetséges értéke 0-255 intervallumba eshet. Ez nem a képernyő 40 karakteres sorában lévő pozíció, hanem annak mértéke, amennyivel a kurzort a sor elejétől elmozgattuk (pl. egymás utáni sortörés nélküli PRINT utasításokkal). A függvény argumentuma lényegtelen. Ez az egyik leghasznavehetetlenebb függvény, bár szöveges kalandjátékokban szokták használni egyfajta nyakatekert szóátvitel megvalósítására. Az EXOS-ban ez alap, így ezen programrészletek egy az egyben törölhetők.
Véletlenszám generálására az RND(<aritmetikai kif.>) függvény szolgál, azaz paramétert kötelező megadni. Az aritmetikai kifejezés előjele határozza meg, milyen eljárás segítségével állítja elő az interpreter a következő számot. Amennyiben az argumentum pozitív, az interpreter "számítja" ki a következő számot, ha az argumentum nulla, a CIA chip óra-regisztereit használja. Ha az érték negatív, a függvény konstans értéket ad. Lényeg a lényeg: a paraméter nélküli RND függvényt kell használnunk, és természetes a program elején a RANDOMIZE utasítást.
Az SPC(<aritmetikai kif.>) adott számú szóközt ír ki. Ha szükség van rá, a TAB függvénnyel, vagy - favágó módon - space karakterek kiíratásával helyettesíthető.
A TI és TI$ a C64 belső órájának segítségével a gép bekapcsolása óta eltelt időt mérik. A TI valós változó, ami azonban csak olvasható. A gép "szabadon futó órája" másodpercenként körülbelül ötvenszer aktualizálódik, és a TI/60 a gép bekapcsolása óta eltelt másodperceket mutatja. A TI$ egy hat karakteres szövegfüzért tárol, amelynek két-két karaktere rendre az órát, a percet és a másodpercet adja. TI$ kezdőértéke értékadó utasítással megadható (pl. TI$="081500"). Szöveges kalandjátékok a legritkább esetben használják időmérésre. Ha mégis szükséges, kivételes esetek kezelésével (HANDLER) helyettesíthető.
File-műveletek
File műveletek végzésére az OPEN, CLOSE, INPUT#, GET# és a PRINT# utasítások szolgálnak. IS-BASIC-ben ugyanazon elvek mentén kezelhetjük értelemszerűen a file-okat, apróbb szintaktikai eltérésekkel. Például az alábbi mentést (4600. sortól) és betöltést (4700. sortól) végző rutin:
4600 V$=CHR$(13):OPEN1,1,1,"m":PRINT#1,I;V$Q;V$N;V$M;V$Y;V$B;V$W;V$D;V$T;V$C;V$G;V$A
4610 FORJ=1TOO:PRINT#1,O$(J)V$P(J):NEXT:FORJ=1TOL:PRINT#1,D$(J):NEXT:CLOSE1:GOTO820
4700 OPEN1:INPUT#1,I,Q,N,M,Y,B,W,D,T,C,G,A
4710 FORJ=1TOO:INPUT#1,O$(J),P(J):NEXT:FORJ=1TOL:INPUT#1,D$(J):NEXT:CLOSE1:GOTO700
így fog kinézni:
4600 LET V$=CHR$(13)
4602 OPEN #1:"m.dat" ACCESS OUTPUT
4604 PRINT #1:I;V$;Q;V$;N;V$;M;V$;Y;V$;B;V$;W;V$;D;V$;T;V$;C;V$;G;V$;A
4610 FOR J=1 TO O
4620 PRINT #1:O$(J);V$;P(J)
4630 NEXT
4640 FOR J=1 TO L
4650 PRINT #1:D$(J)
4660 NEXT
4670 CLOSE #1
4680 GOTO 820
4700 OPEN #1:"m.dat"
4705 INPUT #1:I,Q,N,M,Y,B,W,D,T,C,G,A
4710 FOR J=1 TO O
4720 INPUT #1:O$(J),P(J)
4730 NEXT
4740 FOR J=1 TO L
4750 INPUT #1:D$(J)
4760 NEXT
4770 CLOSE #1
4780 GOTO 700
A Plus4-es játékok módosítása sem bonyolultabb (grafikát tartalmazó játékokkal most nem foglalkozunk), egyetlen említésre méltó eltérés az IF-THEN szerkezetekben használható ELSE-ág. Ez annyira megtetszett az amatőr programozóknak, hogy több programban egyágú szelekciókat is "sikerült" megoldani IF-THEN-ELSE használatával.
Enterpress 2018/4-5.
A dBASE II adatbáziskezelő rendszer ismertetése
I. Alapelemek
A dBASE II (ejtsd: dibéz) - amelynek Enterprise-on a kettes változata fut, PC-n már a négyes is létezik - egy átgondoltan kidolgozott, saját programozási nyelvvel rendelkező adatbáziskezelő rendszer. Lényege, hogy ellátja helyettünk azokat a rendszerközeli feladatokat, amelyek az adatbáziskezelés alapját képezik, és amelyeket programozási szempontból a legnehezebb megoldani. (Nevezetesen: az adatok lemezre írása és karbantartása, a rekordok fizikai szerkezetének kidolgozása, indexelés, keresés.) Olyan magasszintű utasításokat adhatunk ki, mint például: lépj három rekordot előre, keresd meg az első "B"-vel kezdődő nevet, rendezd az adatbázist a "családnév" mező szerint, stb. és nem kell foglalkoznunk azzal, hogy mindezt a rendszer milyen módszerrel csinálja meg. Ha már létrehoztuk az adatbázis szerkezetét, jelentést (REPORT) is képes generálni a program, valamint az adatok kezelésére saját programot is írhatunk, amit aztán bármely felhasználó a rendszer utasításainak ismerete nélkül is kezelni tud. Éppen a programozhatóságban rejlenek a rendszer igazi lehetőségei.
A program csak lemezről működik, és csak a CP/M operációs rendszer alatt. A programhoz egy korrektül, de sajnos német vagy angol nyelven megírt, 24 oldalas help file tartozik. Ez 62 utasítást, 29 állítható paramétert és 17 beépített függvényt tartalmaz.
A rendszer fő maximális paraméterei:
egyszerre nyitott adatállományok száma 16rekordok száma egy adatállományban 65 535mezők száma egy rekordban 32karakterek száma egy rekordban 1 000karakterek száma egy mezőben 254memóriaváltozók száma 64karakterek száma a parancssorban 254függőben lévő GET-ek száma 64REPORT fejléc hossza karakterben 254REPORT-ban szereplő mezők száma 24indexkulcs hossza karakterben 99SUM és REPLACE utasítás műveleteinek száma 5számítási pontosság, számjegyekben 10számábrázolási tartomány, kb. +/-1*10^-63 - +/-1.8*10^63
A végrehajtható programok hossza a leírás szerint "korlátlan". Nos, ez annyiban igaz, hogy a DO parancs segítségével több programrészt ágyazhatunk egymásba, így ha kifutnánk a rendszer szövegszerkesztőjének memóriájából, egy hosszú programot darabokban (modulokban) is tárolhatunk a lemezen. Ez az áttekinthetőség szempontjából is előnyös.
A billentyűzet kezelése sajnos eléggé nehézkes, a billentyű-táblázatot jó mindig kéznél tartani. (A mellékelt INSTALL programmal nem lehet megváltoztatni a beállítást, ez PC terminálok csatolására való.) A használható billentyű-kombinációk:
Valamennyi parancs esetében:
ctrl-X a kurzor a következő mezőre lép (ctrl-F is ugyanezt teszi) ctrl-E a kurzor az előző mezőre lép (ctrl-A is ugyanezt teszi) ctrl-D a kurzor a következő karakterre (jobbra) lép ctrl-S a kurzor az előző karakterre (balra) lép ctrl-G kurzor alatt karakter törlése (jobbratörlés) DEL visszafelé lép, de nem töröl ctrl-V felülírás/beszúrás üzemmód kapcsoló ctrl-Q kilépés a változtatások tárolása nélkül ctrl-W kilépés a változtatások lemezre írásával
EDIT parancs esetében:
ctrl-U törlésre jelölés be/ki ctrl-C a rekordot lemezre írja és a következőre áll ctrl-R a rekordot lemezre írja és az előzőre áll Ezeket APPEND parancs esetében ne használjuk!
BROWSE parancs esetében:
ctrl-U törlésre jelölés be/ki ctrl-B a képernyőablak jobbra mozgatása ctrl-Z a képernyőablak balra mozgatása ctrl-C a következő rekordra lép ctrl-R az előző rekordra lép
MODIFY COMMAND parancs esetében:
ctrl-T sor törlése a szöveg felzárásával ctrl-Y sor törlése helykihagyással ENTER lefelé lép a sorokon ctrl-C fél képernyőt lép lefelé ctrl-R felfelé lép a sorokon ctrl-N üres sor beszúrása a kurzor alatti sor helyére
APPEND parancs esetében:
ENTER amikor a kurzor üres rekord elején áll, adatbevitel befejezése
Parancssorban:
ctrl-R az utolsó parancs végrehajtása újra
A programot a CP/M (IS-DOS) betöltése után a dBASE paranccsal indíthatjuk, és ha végeztünk a munkával, a QUIT paranccsal szállhatunk ki belőle. A rendszer promptja egy pont. Ha nagyon összekutyulnánk a képernyőt, ERASE-zel törölhetjük. Ha elrontottuk egy parancs beírását, a rendszer UNKNOWN COMMAND, vagy SYNTAX ERROR üzenettel válaszol, és megkérdezi, hogy kívánjuk-e módosítani a parancsot. (Módosítani nem érdemes, mert körülményesebb, mint újraírni az egészet.)
Új adatbázist a CREATE paranccsal hozhatunk létre. Ha nem adunk meg utána nevet, akkor rákérdez. A kiterjesztést nem kell megadni, ez automatikusan DBF, azaz adatbázis lesz. Ezután egy fejlécet kapunk, és a megjelenő mezősorszámok mellett meg kell adnunk, hogy milyen mezőket tartalmazzon az adatbázisunk. Először írjuk be a mező nevét, majd a típusát. A mezők típusa lehet
A típus után következik a mező hossza karakterekben. Számmezőnél, ha törtszámot is várunk, a tizedespont utáni helyek számát is meg kell adni. A logikai mezők értéke igaz (true, t) vagy hamis (false, f) lehet, így ezek tárolására egy karakter is elég. A bevitt paramétereket vesszővel kell elválasztani.
ENTER-rel fejezzük be a rekordszerkezet kialakítását. (Egy kész szerkezet később szükség esetén módosítható, ennek módszerét később mutatom be.) Ekkor a program megkérdezi, hogy akarunk-e rögtön adatokat bevinni. Ha igen, akkor APPEND (hozzáfűzés) üzemmódba kerülünk, és kitölthetjük az üres képernyőmaszkot. Az utolsó mező kitöltése után a következő rekordra áll a rendszer, egészen addig, amíg ENTER-rel (vagy bármilyen ctrl-billentyűkombinációval, szabálytalanul) be nem fejezzük az adatbevitelt.
A kész adatbázist a USE paranccsal lehet megnyitni, azaz beolvasni a lemezről, és ugyanezzel lehet lezárni, vagyis lemezre tárolni is a munka befejezésekor. (A változtatások csak ekkor tárolódnak le teljesen, ezért hosszabb munka esetén érdemes többször lezárni és újra megnyitni az állományt.) Ha az adatbázist kezelő parancsot adunk ki olyankor, amikor üres a memória, a program rákérdez, hogy melyik adatbázist olvassa be a lemezről, és ezután ezen hajtja végre az utasítást.
A bevitt adatokat később megnézhetjük és módosíthatjuk A BROWSE parancs egymás alá írja ki a rekordokat, köztük a fent leírt billentyűkombinációkkal mozoghatunk. Módosítani is lehet. Ha törlésre jelölünk egy rekordot, akkor a képernyő felső sorában a DELETED felirat jelenik meg, mindig, amikor erre a rekordra lépünk. Ez egyelőre csak megjelölés, a végleges törlést a PACK parancs végzi el, amely az összes megjelölt rekordot eltávolítja az adatbázisból.
APPEND paranccsal az adatbázis végéhez fűzhetünk újabb rekordo(ka)t, amely(ek) képernyőmaszkját a szokásos módon tölthetjük ki. Az APPEND BLANK parancs egy üres rekordot fűz be, amelyet egyelőre nem töltünk ki. (Programozáskor hasznos, ha az adatokat a felhasználó írja be.) Az EDIT paranccsal egy adott sorszámú rekordot szerkeszthetünk. Ha nem adjuk meg a számát (pl. EDIT 3), akkor a program rákérdez. Ha nem létező számot adunk meg, RECORD OUT OF RANGE hibaüzenetet kapunk.
Az egyes rekordokat kiírathatjuk a LIST, vagy DISPLAY - rövidítve DISP - parancsokkal is. Önmagában kiadva a LIST az összes rekordot felsorolja, a DISP csak az aktuálisat írja ki, amelyiken éppen állunk. Paraméterek is megadhatók utánuk, pl: LIST (DISP) CSALADNEV - ha van CSALADNEV nevű mezőnk, akkor csak azt írja ki. Több mezőnév is megadható, vesszővel elválasztva. LIST (DISP) ALL OFF - valamennyi rekord kiírása, de a rekordsorszám nélkül. A törlésre kijelölt rekordokat csillaggal jelzi a rendszer.
A rekordok között a SKIP paranccsal mozoghatunk. Ez alapértelmezésben egyet lép előre, de megadható utána a lépés is, pl. SKIP -2 két rekordot lép hátra. A törlésre kijelölt rekordokat kihagyja! Ezekre csak GOTO (rövidítve GO) [sorszám] paranccsal lehet rálépni. Amelyik rekordon éppen állunk, azt a DELETE-tel törlésre jelölhetjük, RECALL-al pedig visszahívhatjuk, ha meggondoltuk magunkat. Ezek is paraméterezhetők, pl.: DELETE RECORD 15 - a 15. rekord törlése, DELETE ALL FOR CSALADNEV="Kovacs" - az összes "Kovacs" tartalmú családnév mezőt tartalmazó rekord törlése, RECALL ALL - az összes törlésre kijelölt rekord helyreállítása.
Az adatbázis szerkezetét a DISPLAY STRUCTURE (rövidítve DISP STRU) paranccsal írathatjuk ki. Ekkor megjelenik az adatbázis neve, a rekordok száma, az utolsó módosítás dátuma, a használati prioritás (akkor érdekes, ha több adatbázis van a memóriában egyszerre), a mezők sorszáma, neve, típusa és hossza, valamint a mezők összes száma.
A DISPLAY MEMORY parancs a használt memóriaváltozókat írja ki.
Matematikai műveletek eredményét és változók tartalmát kérdőjellel írathatjuk ki. Pl.: ? 6/3 eredménye 2 lesz. (A kérdőjel után szóközt kell hagyni.)
A lemezen található adatbázisokat sorolja fel a LIST FILES parancs, a bennük levő rekordok számával és az utolsó módosítás dátumával együtt. Ha a lemezen (az aktuális tartalomjegyzékben) található összes állomány listájára vagyunk kíváncsiak, akkor írjuk be: LIST FILES LIKE *.* (egyéb maszk is megadható). A DELETE FILE [név] paranccsal törölhetünk egy állományt a lemezről. Ha nem adunk meg kiterjesztést, akkor a program DBF-et keres. Ha mást akarunk törölni, a kiterjesztést is írjuk hozzá. A program közli, hogy az adott állományt törölte, vagy nem találta meg.
Az adatbázist több mező szerint is indexelhetjük (sorba rendezhetjük), úgy, hogy különböző indexállományokat készítünk hozzá. Pl: INDEX ON CSALADNEV TO CSALAD. Itt a "CSALADNEV" a mező neve, ami szerint rendezni akarunk, a "CSALAD" pedig annak az indexállománynak a neve, amit a program a lemezen létrehoz. Ha ezután kilistázzuk a rekordjainkat, láthatjuk, hogy az ABC-sorrend valóban létrejött. Ha legközelebb megint használni akarjuk az indexelt adatbázist, USE CIMEK INDEX CSALAD paranccsal kell megnyitni! (Ahol a "CIMEK" természetesen az adatbázis neve, amivel létrehoztuk.) Lezárni továbbra is sima USE paranccsal lehet. VIGYÁZAT! Ha egyszer indexállomány nélkül nyitjuk meg az adatbázist, változtatunk rajta és lezárjuk, az indexállomány nem lesz érvényes. A REINDEX paranccsal a legközelebbi megnyitáskor aktualizálhatjuk az indexet. Persze, mindig elkészíthetjük az indexállományt teljesen újra, hiszen csak egyetlen parancsot kell kiadni hozzá. Az indexállomány kiterjesztése a lemezen automatikusan NDX lesz. Ha több indexünk van, megnyitáskor valamennyit soroljuk fel! Pl. USE CIMEK INDEX CSALAD,TELEFON,LAKCIM. Próbáljunk a lemezes állománynak (akár csak egy betűvel is) eltérő nevet választani, mint a rekordban használt mezőknek, hogy ne zavarjuk meg a programot. Mező és memóriaváltozó neve sohasem lehet ugyanaz!
Ha már van egy kulcsmezőnk, akkor aszerint kereshetünk a FIND paranccsal. Pl. FIND "Kovacs" megkeresi azt az első rekordot, amelyben a CSALADNEV kulcsmező tartalma "Kovacs". Ha több ilyen is van, SKIP-pel kell továbblépnünk, hogy a következőket is megtaláljuk. Csak a szó eleje szerint is lehet keresni, pl. FIND "Ko". A kis- és nagybetűket megkülönbözteti a program!
Ha több indexünk van és nem az elsőt akarjuk használni, a SET INDEX TO parancsot kell kiadni, ami után az index-állomány neve áll.
Ha a rekordjainkat fizikailag is át akarjuk rendezni, használjuk a SORT parancsot. Pl: SORT ON TELEFON TO TEL a használatban lévő adatbázist a TELEFON mező szerint rendezi, és egy új példányt készít belőle a lemezen TEL.DBF néven. A mezőnek, ami szerint rendezünk, nem kell kulcsmezőnek lennie. Ha megadjuk a DESCENDING paramétert is a végén, akkor csökkenő sorrendet alakít ki. (Megérti az ASCENDING - növekvő sorrend - paramétert is, de mivel ez az alapértelmezés, nem kell külön kiírni.)
Végül, néhány a beállítható paraméterek közül:
II. A rendszer programozása
Programok készítésére a MODIFY COMMAND parancs szolgál. Ezután meg lehet adni a program nevét; ha nem adjuk meg, rákérdez. Amennyiben van már ilyen nevű program a lemezen, akkor azt betölti. Ha nincs, kiírja, hogy NEW FILE, és csak ezután jelentkezik be a beépített szövegszerkesztő.
(Megjegyzés: A program szövege normál szöveges állományként tárolódik, tehát nem kódolva, mint a BASIC programok.)
Minden utasítást külön sorba kell írni. Az első sor ne kezdődjön szóközzel! A többinél már nem számít, tehát a szöveget tetszés szerint tabulálhatjuk.
A beírás végén a programot a CTRL-W kombinációval tároljuk el, amivel ki is lépünk a szerkesztőből. Ezután a programot a DO <PROGRAMNÉV> paranccsal futtathatjuk.
Legjobb, ha az utasításokat néhány példaprogramon keresztül ismerjük meg. Az első program megnyit egy címeket tartalmazó adatbázist, az első rekordra áll, beírat egy család- és egy keresztnevet a kezelővel, majd tárolja ezeket a rekordban.
use CIMEK index CSALAD
go top
store CS_NEV to CS
store K_NEV to k
@ 2,2 say "Csaladnev:" get CS
@ 3,2 say "Keresztnev:" get K
read
replace CS_NEV with CS
replace K_NEV with K
disp all
use
A programban a változónevek nagybetűvel, az utasítások kisbetűvel vannak írva.
Az első sorban megnyitjuk a CIMEK nevű adatbázist, ami a CSALAD indexállománnyal van indexelve. A "go top" utasítás az első rekordra áll. Ezután kezdőértéket adunk két változónak: a CS-ben a beolvasott családnevet, a K-ban a keresztnevet tároljuk majd. (Ha kezdőértéket nem adunk, a változó nem létezik, és futás közbeni hibaüzenetet kapunk.) A szöveges változókat nem kell a név után írt "$" jellel megkülönböztetni, értékadáskor dől el, hogy a változó milyen típusú lesz.
Vegyük észre, hogy a változók kezdőértékeként tárolt neveket abból a rekordból olvassuk ki, amelyen állunk. (Feltételezzük, hogy a CS_NEV a családnév mező, a K_NEV pedig a keresztnév mező neve a rekordban.)
Arra mindenki rá fog jönni, hogy a következő utasítások mire valók. A "say" egy szöveget ír ki a képernyőre a megadott koordinátáktól kezdve. A @ jel után egy szóközt kell hagyni! A "get" pedig, természetesen, a változók beolvasására való, azaz a BASIC INPUT utasításának felel meg. Önmagában azonban még nem olvas be semmit, csak elkészíti a képernyőmaszkot, amelyben annyi helyet hagy, amennyi a változó kezdőértékének hossza volt. A tényleges beolvasást a következő sorban a "read" utasítással kezdjük meg. Ilyenkor a rendszer lehetővé teszi, hogy a kezelő a képernyőmaszkba beírja az adatokat, az egyes mezők között akármilyen sorrendben lépkedve. A bevitel végét az utolsó mezőben lenyomott ENTER jelenti.
Most látjuk értelmét annak, hogy az előbb a változókba a rekord mezőinek tartalmát tároltuk. Ugyanis a "get" utasítás a beolvasott változók eredeti tartalmát kiírja a képernyőmaszkba, így mindig látjuk, hogy mit módosítunk. Amikor lenyomjuk az ENTER-t, a rendszer mindig azt a szöveget tárolja el, ami éppen a képernyőn látható.
E tulajdonsága miatt a "get" beolvasás nélkül, csak a mezők tartalmának megjelenítésére is jó. Ilyenkor a kiírás után nem a "read", hanem a "clear gets" utasítást kell kiadni.
Az utolsó lépésben a mezők tartalmát kicseréljük (replace) a beolvasott változókra. (Az újonnan beírt nevet a rendszer az index szerint be is rendezi.) Ezután ellenőrzésképpen kiíratjuk az összes rekordot (disp all) a képernyőre, majd lezárjuk az adatbázist.
Természetesen egy valódi programban bizonyos szempontok szerint kell kikeresni a módosítandó rekordot, és a mező tartalmának átírása előtt a kezelőnek biztonsági kérdést illik feltenni. Nézzünk most egy "menükészítő" példaprogramot, amelynek segítségével a kezelő választhat a program szolgáltatásai közül. Tegyük fel, hogy a menüpontokat már kiírtuk a képernyőre (say).
accept "Valasszon!" to W
do case
case w="1"
do RESZ_1
case w="2"
do RESZ_2
case w="3"
do RESZ_3
otherwise
@ 10,2 say "Ilyen pont nincs!"
endcase
Nem nehéz felismerni a BASIC-ből már ismert CASE ágak megfelelőit. A RESZ_1, RESZ_2 és RESZ_3 alprogramok nevei, amelyeket külön írtunk meg és a lemezen tároltunk. Az "otherwise" (angolul "egyébként") természetesen az ELSE ágnak felel meg. Az első sor "accept" utasítása kiírja a megadott szöveget a képernyőre, majd egy billentyű lenyomását várja, és azt tárolja a W változóban.
A következő program az összes rekord tartalmát egyenként kiírja a képernyőre, és vár, amíg a kezelő elolvassa azokat és lenyom egy billentyűt.
do while .not. eof
disp
accept "Ha elolvasta, nyomjon meg egy billentyut!" to W
skip
enddo
Ciklusszervezést látunk, ami már szintén ismerős. Az első sor azt jelenti, hogy a ciklust addig kell ismételni, amíg még nem értük el (.not.) a file végét (eof = end of file). A relációs operátorokat (not, and és or) valóban két pont közé kell tenni, nem sajtóhiba. Kiírjuk az aktuális rekordot (disp), majd billentyűlenyomásra várunk, végül a következő rekordra lépünk (skip). Egyébként várakozásra a rendszer a "wait" parancsot is ismeri, ami WAITING... üzenetet ír a képernyőre, de ezután más szöveg nem adható meg.
Végül ismerkedjünk meg a feltételes utasítással is. Írassuk ki az összes rekord tartalmát, kivéve azokat, ahol a családnév mező tartalma "Kovacs". Az alábbi program (amelyet a HELP szövegből alakítottam át) ezt egy kissé csavarosan oldja meg, de működik.
do while .not. eof
if CS_NEV="Kovacs"
skip
loop
endif
disp
skip
enddo
Vagyis: ha a családnév Kovacs, akkor kihagyjuk ezt a rekordot (skip), és visszaadjuk a vezérlést a "do while" utasításra (ezért ilyen ravasz a példa, hogy a "loop" használatát is be lehessen mutatni vele). Ellenkező esetben az "if" utasítás utánra kerül a vezérlés, ahol is kiíratjuk a rekord tartalmát és csak utána lépünk a következőre.
Kissé egyszerűbben ugyanez:
do while .not. eof
if CS_NEV<>"Kovacs"
disp
endif
skip
enddo
Természetesen az "if" utasításnak "else" ága is lehet. Hogy még mindig ennél a példánál maradjunk:
do while .not. eof
if CS_NEV="Kovacs"
remark Kihagyva.
else
disp
endif
enddo
Könnyű kitalálni, hogy a "remark" utasítás az utána következő szöveget kiírja a képernyőre. Itt jó ezt használni, mert nem kell neki koordinátát adni, mint a "say"-nek. A szöveget nem kell idézőjelbe tenni.
Még egy kis példa, kommentár nélkül:
remark Nyomd meg!
wait
remark Na vegre!
A "say" és a "get" utasítás után egyaránt használhatunk kiírási mintát. Erre a két utasítás esetében két különböző kulcsszó szolgál, amelyeknek más-más mintát adhatunk meg:
@ <koordináták> say <változó- vagy mezőnév> using "kép"
@ <koordináták> say <változó- vagy mezőnév> get <változó- vagy mezőnév> picture "kép"
@ <koordináták> get <változó- vagy mezőnév>
"Using" után megadható paraméterek:
Bármely egyéb jellel a mező/változó tartalmát a képernyőn felülírja.
"Picture" után megadható paraméterek:
Bármely egyéb jel a kiírásban elválasztójelként jelenik meg, és ezeket a beolvasáskor a kurzor átlépi. Pl. telefonszámba tehetünk kötőjeleket, vagy a körzetszámnak zárójeleket:
picture "+(###)-##-##-##"
A programban használt memóriaváltozók értékeit bármikor lemezre menthetjük (save to <filenév>), majd visszaolvashatjuk (restore from <filenév>). A "release" utasítás pedig a változókat törli és az általuk használt memóriaterületet felszabadítja.
Ha nyomtatni szeretnénk, adjuk ki a "set format to print" utasítást. Ezután minden "say" a nyomtatóra fog írni, egészen addig, amíg "set format to screen" utasítással vissza nem állunk a képernyőre.
A memóriában egyszerre két adatbázis is lehet. Ilyenkor a két adatbázis adatterülete között a "select primary" (elsődleges) és "select secondary" (másodlagos) utasításokkal lehet oda-vissza lépkedni. Változóterület csak egy van, tehát a két adatbázishoz nem rendelhetünk azonos nevű memóriaváltozókat.
III. A beépített függvények
chr(szám) azt a karaktert adja, amelynek ASCII kódja a megadott szám. int(szám) a megadott tizedesszám egész része. len(string) a karakterlánc hossza. trim(string) a karakterláncról a végén levő szóközöket levágja. val(string) a karakterlánc számértéke. !(string) a karakterláncot nagybetűsíti. file(filenév) igaz, ha a lemezen a megadott file létezik, hamis, ha nem. type(mezőnév) a megadott mező típusa (karakteres, szám vagy logikai, azaz C, N vagy L). date() a rendszerdátumot adja meg. str(számértékű kifejezés, mezőszélesség, tizedesek száma) a megadott számot vagy a kifejezés értékét karakterlánc formára alakítja, ahol a mezőszélesség a kívánt karakterlánc összes szélességét, a tizedesek száma pedig ezen belül a tizedesjegy-helyek számát adja meg. rank() egy karakter ASCII-kódját adja meg.
Természetesen ahol a felsorolásban a zárójelben "string" szerepel, ez lehet szöveges változó, vagy szöveg típusú mező neve is.
IV. Jelentés (report) generálása
A rendszer a "report" parancsra megpróbál egy kezdetlegesen formázott jelentést készíteni a rekordjainkról. Az utasítás kiadása után az alábbi kérdéseket teszi fel:
Enter options, m=left margin, l=lines/page, w=page width.
Erre be kell írnunk, hogy hol legyen a bal margó, hány sor legyen egy oldalon, és milyen széles legyen egy oldal. Például: m=2, l=15, w=50.Page heading required? Y/N
Kérünk-e fejlécet az oldalra? Ha igen, a következő kérése, hogy gépeljük be:
Enter page heading.Double space report? Y/N
Dupla sortávolsággal írja-e a jelentést?Are totals required? Y/N
Akarunk-e összegezni? Ha igen, akkor további kérdések következnek, amelyek során megadhatjuk, hogy mely mezők tartalmát akarjuk összeadni.Col. width, contents
001
Itt írjuk be, hogy melyik oszlopban mi legyen, és milyen szélességben. Pl:
001 20, CS_NEV
002 10, K_NEV
003 <ENTER>
Minden oszlop megadása után rákérdez a föléje írandó fejlécre is (Enter heading).
Ha mindez megvan, a formátumot egy file-ba tárolja, FMT kiterjesztéssel. A nevét nekünk kell megadnunk, és ezt a formátumot ezek után máskor is használhatjuk. Ha minden kész, a jelentés megjelenik a képernyőn. Ez persze csak hevenyészett tájékozódásra jó, szebb jelentéseket programból lehet készíteni.
V. Adatbázis szerkezetének módosítása
Ha már adatok vannak az adatbázisunkban és akkor derül ki, hogy a szerkezetén módosítani kell (mezőket törölni, hozzáadni vagy a hosszukat változtatni), az alábbi eljárást kövessük (programból nem lehet, egymás után kell kiadni a parancsokat):
.use CIMEK
megnyitjuk az adatbázist,
.copy structure to IDEIG
ideiglenes állományba másoljuk a szerkezetét,
.use
lezárjuk az adatbázist. (*)
.use IDEIG
megnyitjuk az ideiglenes állományt,
.modify structure
módosítjuk a szerkezetet
.append from CIMEK
az adatokat átmásoljuk az ideiglenes állományba
.delete file CIMEK
töröljük a lemezről a CIMEK.DBF állományt.
.use
lezárjuk az ideiglenes állományt,
.rename IDEIG to CIMEK
átnevezzük a létrehozott új állományt a régi névre.
(Megjegyzés: Ha az adatokkal tele állomány szerkezetét módosítjuk, az adatok elvesznek. Ezt az eljárást teljes egészében a HELP szövegből vettem. A csillaggal jelölt sort én tettem hozzá, mert az elsőként megnyitott adatbázist az új megnyitása előtt szerintem le is kéne zárni.)
Mielőtt ezt kipróbáljuk, készíthetünk biztonsági másolatot az adatainkról a "copy to <állománynév>" paranccsal. Visszaolvasás az "append from <állománynév>" paranccsal lehetséges.
Szalontai Andrea - Enterpress 1994/1-3.
Címezzünk
pontosan!
A félreértések elkerülése végett nem a Magyar Posta bérelt fel, hogy nagy példányszámú,
sűrűn megjelenő lapunkon keresztül serkentse kis hazánk némileg slendrián népét
a postai küldemények címzettjének akkurátusabb feltüntetésére, most is kedvenc
ENTERPRISE-unkról folyik majd a szó.
Mint tudjuk, gépünk 4 megabájt memóriát, és 64 kilobájtnyi I/O-egységet képes
megcímezni, ez egy ilyen kis masinától szép teljesítmény, elvileg el is férne
minden bővítés ekkora nagy helyen. Gond akkor lép fel, ha két kártya, mely külön-külön
pl. csak 4 bájtot fogyasztana, ugyanarra a 4 bájtra veti ki a hálóját. Ennek
rendszerint lefagyás, súlyosabb esetben multimédia (különböző fény- és hangjelenségek),
vagy akár az ENTERPRISE elhalása a következménye. Ezért igen fontos, hogy a
nagy kártyagyártók (mint pl. én: 190 cm, és 95 kiló), és egyéb buherálók (nem
csak ZozoHard!) megállapodjanak a piac felosztásában. Ez ügyből kifolyólag az
alábbiakban megteszem javaslatomat:
Memória
Szegmensek (hex) | Eszköz |
00 - 03: | EXOS (a gép belsejében, fix) |
04 - 07: | cartridge |
10 - 1F: | microTEAM-kártya 1. EPROM |
20 - 2F: | EXDOS (microTEAM-kártya 2. EPROM) |
30 - 3F: | microTEAM-kártya 3. EPROM |
40 - 5F: | microTEAM-kártya 512 KB RAM |
60 - 63: | EPROM / SRAM-bővítő kártya SRAM |
64 - 77: | EPROM / SRAM-bővítő kártya EPROM |
10 - 1F, 30 - 7F: | eredeti régi EPROM-bővítő kártya |
70 - 7F, 90 - DF: | buherált régi EPROM-bővítő kártya |
78 - AF, F0 - F7: | 2. 1 MB-os RAM-bővítés |
B0 - EF: | 1. 1 MB-os RAM-bővítés |
EC - F7: | 320 KB belső RAM-bővítés egy része |
F8 - FB: | 64 KB a gép belsejében, bővítőkártyán, vagy a 320 KB belső bővítés másik része |
FC - FF: | 64 KB az alaplemezen (fix) |
08 - FB: | egyéb buhera és takera |
Mint látható, itt máris összeveszések történtek. Persze nem annyira vészes a dolog, hiszen pl. akinek belső 320 KB-os RAM-bővítése van, annak tudok pl. A0-DF közé eső 1 MB-os RAM-bővítőt készíteni, ha nagyon muszáj. A helyzetet tovább javítandó, minden régi EPROM-bővítő kártyát amennyiben jogos tulajdonosa igényt tart rá - az új címzésének megfelelően (60 - 77) átalakítok. Ez sajnos nincs ingyen, a szükséges GAL miatt, az ár 400 Ft. Ezenkívül kell még a játékhoz a ZozoSoft-féle EXOS 2.3, amely minden szegmenst végignéz rezidens rendszerbővítőket keresve (egész ügyes), ez csekély 1000 Ft-ba kerül. Persze ha valakinek jól működik a rendszere, és nem kíván (vagy nincs pénze) újabb bővítéseket beszerezni, használja egészséggel továbbra is úgy, ahogy van!
I/O cím | eszköz |
00 - 07: | soros (egér-) illesztő kártya |
10 - 1F: | lemezvezérlő kártya |
30 - 37: | 48-vonalas digitális I/O-kártya |
40 - 4F: | Spectrum-emulátor |
50 - 57: | koprocesszor-kártya (próbapéldány) |
60 - 62: | XT-billentyűzet illesztő |
70 - 71: | elemes óra/naptár |
80 - 8F | NICK |
A0 - B7, BF | DAVE |
Aki tud egyéb kártyákról, és azok címeiről, kérem, tegye közkinccsé, mindannyiunk érdekében! Ha pedig valaki kártyát épít, vagy átépít, válasszon még üres címtartományokat, és választását lehetőleg terjessze (pl. lapunkban), megakadályozandó a későbbi problémákat! Végül, ha valaki merészelne egyéb, a fentiektől eltérő javaslattal előállni, ám tegye! Valahogy majd csak megegyezünk...
Mészáros Gyula - Enterpress 1994/1-2.
AZ ENTERPRISE rendszer-szegmens rögzített területének címei és azok funkciójaABD1-D2: A csatornapuffer-kijelölés EXOS-funkció ide menti el az SP-t.
AC3B-3C: STACK_LIMIT változó alapértéke. Idáig terjedhet a verem.
ACE7-B216: Az EXOS saját rendszer-verme. (kezdőérték B217)
B217-2F: A kernel segédrutinjai. Ezeken keresztül hívja meg azokat a rutinokat, melyek 3. lapú címekkel más szegmensen futnak (pl. rendszerbővítők; az 1. szegmensen lévő EXOS-rutinok), valamint az a rutin amelyen keresztül a vezérlés elhagyja a kernelt.
B230-50: A különleges státuszüzenet (ha az ST_FLAG tartalma 2AH).
B251-52: EDITOR változó címe-2
B253-8C: EDITOR munkaterület: (angol gépnél)
B253-54: Szövegterület kezdőcíme.
B255-56: Szövegterület vége. (vonalzósor kezdőcíme-1)
B257-58: Szövegmutató.
B259-5A: Szövegmutató.
B25B-5C: Szövegmutató.
B25D-5E: Szabad terület nagysága.
B25F: Editor video csatornaszám.
B260: Editor keyboard csatornaszám.
B261: Editor csatornaszáma különleges funkciónál, szövegfájl kimentés / betöltés esetén C értéke vagy a hiba kódja.
B262: Editor ESC ;80=ESC jelzés; <80=ESC szekvencia karakterszámláló
B263: Kurzor beállítás Y koordináta.
B264: Kurzor beállítás X koordináta.
B265: Video Y
B266: Video X
B268: Vonalzósor állapota. (0=ki, 1=be)
B26D: Bal margópozíció alapértelmezése.
B26E: Jobb margópozíció alapértelmezése.
B26F: Bal margópozíció.
B270: Jobb margópozíció.
B271: Margó-feloldás jelző. (0=érvényes, 2A=alapértelmezés)
B272: Színkód+128
B273: Kurzor Y
B274: Kurzor X
B277: Vezérlőkarakter kódja.
B27B: Hibajelző (b0=1 videó csat., b1=1 keyboard csat.)
B27D: Szövegpuffer vezérlőkarakterek kiírásához.
B27E: Puffer.
B27F-80: Puffer.
B282: Módosított FLG_EDIT értéke.
B283: Számláló.
B286: Beszúrás-felülírás jelző
B287: Újraformázás-kiegyenlítés jelző.
B288-89: IX értéke.
B28A: P1-es szegmens száma.
B28B: Használat alatti EDITOR csatorna száma.
B28D-E2: TAPE munkaterület:
B28D: A 0038 cím eredeti tartalma.
B28E: Az aktuálisan működtetett távvezérlő.
B28F: Olvasásra megnyitott fájl csatornakódja +1 vagy 0 ha nincs.
B290: Írásra megnyitott fájl csatornakódja +1 vagy 0 ha nincs.
B291: Az input fájl távvezérlője: 00=REM1, más=REM2.
B292-AE: Az input fájl neve.
B2AF: Az output fájl távvezérlője: 00=REM1, más=REM2.
B2B0-CC: Az output fájl neve.
B2CD-E: Az input pufferben lévő bájtok száma.
B2CF-D0: Az output pufferben lévé bájtok száma.
B2D1-2: A input puffer aktuális címe.
B2D3-4: Az output puffer aktuális címe.
B2D5: EOF-jelző: <>00= a fájlból nem lehet olvasni.
B2D6: Az olvasott szelet típusa: 00=adat, FF=fej.
B2D7: Adat a csatornalezárásnak: 00=van még adat a pufferben.
B2D8: A védelmi bájt értéke: 00=a védelem bekapcsolva.
B2D9: 00=nem volt hiba, FF=CRC hiba.
B2DA-DB: Az SP regiszterpár átmeneti tárolója.
B2DC: A kimentés jelszintje (a 0ABH portya kikerülő érték).
B2DD-E0: Konstansok a megfelelő felvételi sebességhez (a 0A0H porta).
B2E1: A státuszsor eredeti COL2 palettaszíne.
B2E2: A státuszsor eredeti COL3 palettaszíne.
B2E3-47F: SOUND munkaterület:
B2E3-F2: Az A0-AF portok aktuális értékei.
B2F3: Foglaltság jelző. 0=nincs megnyitva. Használat alatt a puffer szegmensszáma az első lapon.
B2F4-F5: A burkoló tárterület kezdőcíme. (0=nincs)
B2F6-F7: A burkoló tárterület végcíme / várakozási OR kezdőcíme.
B2F8: SYNC
B2FA: Hangforrás sorszáma.
B2FB-37A: Hangsorok 8 bájtonként.
B37B: 6*fázisok száma
B37C-7D: hangkezelő escape-szekvenciáit kezelő rutin címe.
B37E-7F: A hangkezelő escape-szekvencia argumentum következő bájtjának címe.
B380: Hangkezelő ESC jelző / számláló. 0=szabad karakter olvasódik be, 1-7F=ESC utáni vezérkarakter olvasódik be, 80-FF = a még beolvasandó paraméterbájtok számának kettes komplemense.
B381-47F: SOUND pufferterület: (ESC+vezérkód utáni paraméterek számára)
B480-C7F: Video munkaterület:
B480-8FF: Karakterkészlet (a CH128 módú karaktergenerátor)
B900-B1F: Az alapértelmezés szerinti LPT. (1+27+6 sor * 16 bájt)
BB20-46: Nem használt.
BB47: Az attribútum jelzőbájt másolata (IX-85)
BB48-49: Terület nagysága. (IX-54), (IX-53)
BB4A: b0-b3=tinta b4-b7=papír (IX-81)
BB4B: Video_mode (IX-2)
BB4C: Vonaltípus (IX-79)
BB4D: Vonalmód rutin paramétere (IX-80)
BB52-53: Y koordináta.
BB54-6B: Puffer a pontok számolásához.
BB6C-6D: X oldal hossza.
BB78-79: Rutin címének tárolója.
BB7E-7F: Ellipszis sugár X.
BB84-85: Rutin címének tárolója.
BB8E-8F: A másodlagos kijelzés RAM címe (IX-48), (IX-47)
BB90-91: Fő kijelzés RAM címe (IX-50), (IX-49)
BB92-93: Veremmutató tárolására.
BB94: PAPER vonalbájt.
BB95-96: X oldal karakteres hossza.
BB97: Pontbitek.
BB98: Távolság jobbra.
BB99-9A: Pont videocíme.
BB9B-9C: Előző pontszám.
BB9D-9E: Jelzőbitek és a letett pontok száma.
BB9F: Szegmens száma.
BBA2-BC: 27 bájt: csatornaszámok az LPTsorok kirakására.
BBBD-D7: 27 bájt: csatornán belüli sor száma az LPT-hez.
BC80-97: NET-SERIAL munkaterület:
BC80-81: A CRC regiszter.
BC82: A soros pufferben a következő bájtra mutató ofszet.
BC83: A soros pufferben lévő bájtok száma.
BC84-85: Várakozási ciklus-számláló a megfelelő baud értékhez.
BC87: SERIAL foglaltság jelző. (0=nincs csatorna)
BC90-D0F: NET eszközök leírói 4 bájtonként. (max. 32 gép 4*32=128 bájt)
BD16-EB7: KEYBOARD munkaterület: (angol gépnél)
BD16-1F: A legutoljára leolvasott billentyűmátrix töröli SHIFT-ekkel.
BD20-29: Az előző billentyűmátrixból képzett segédadatok.
BD2A-EA9: A funkcióbillentyű sztringek 24-24 bájton.
BEAA: Ha <>0 akkor a BEAE tartalma érvényes (van éppen lenyomott billentyű).
BEAB: Ha FF akkor HOLD állapot van érvényben.
BEAC: A váltóbillentyűk állapota: b1=SHIFT, b2=CTRL, b3=ALT.
BEAD: Ha FF akkor van nyitott billentyűzetcsatorna.
BEAE: Az éppen lenyomott billentyű kódja.
BEAF: Ha FF akkor LOCK állapot van érvényben.
BEB0-B1: A billentyűzet-puffer legfelső elemének címe.
BEB2: A pufferben tárolt billentyűkódok száma.
BEB3: Számláló a billentyűkésleltetés megvalósításához.
BEB4: Számláló az automatikus ismétlés megvalósításához.
BEB5-B6: Annak a billentyűsornak a címe, amelyben megváltozott állapotú billentyű van.
BEB7: A megváltozott állapotú mátrixsor képe.
BEB8-BFFF: Kernel terület
BEB8-DF: 40 bájtos státuszsor memória
BEE0-F07: Az EXOS ide generálja az általa kezelt hibaszöveget.
BF08-17: A betöltés alatt álló modul fejrésze.
BF18: Az alapértelmezésbeli egységszám.
BF19-35: Az alapértelmezésbeli eszköznév a határoló ":" és egységszám nélkül.
BF36-53: Eszköznév-puffer: eszköz- / fájlnév megadásakor itt képződik a kernel által kezelhető eszköznév a határoló ":" és egységszám nélkül.
BF54-71: Fájlnév-puffer: eszköz- / fájlnév megadásakor itt képződik a kernel által kezelhető fájlnév.
BF72-77: Az EXOS által kezelt naptár és óra. (BCD)
BF72: Másodperc.
BF73: Perc.
BF74: óra.
BF75: Nap.
BF76: Hónap
BF77: Év-80.
BF78: Indításjelző: b0=1 akkor a ROM-bővítők már jelöltek ki RAM-ot. Nulla esetén: EXOS 1A=Rendszerbővítők hívása hidegindítással. (C=10,20,60) EXOS 00=Rendszerbővítők RAM kiutalása.
BF79: Futásjelző: b0=1 akkor egy periféria futás közben van. b7=1 akkor a kernel futás közben van, tehát nem kell áttérni
a rendszer-veremtárra. (innen állapítja meg, ha rekurzívan fut)
BF7A-7B: A kernel itt tárolja az SP belépés elölti értékét.
BF7C-7D: A kernel itt tárolja a HL regiszterpát belépés előtti értékét.
BF7E: 1. ROM szegmens ellenőrző kód: / kontroll-summa. Értéke: A7H. Képzése: ACH XOR (01:FFD8-tól 19H össze XOR-ozva). (időnként megszakításból ellenőrzi a rendszer)
BF7F: A relokálható betöltés futási lapja (gyakorlatilag a cím MSB).
BF80: A csatornaszám, ahonnan a modult be kell tölteni (nincs eggyel megnövelve!).
BF81-83: A csatornaláncban történő kereséskor a következő elem címe. A periféria-alprogramokat hívó szubrutin itt várja a csatornaleíró 24 bites első lapú címét.
BF84-8E: A csatornapuffer-kijelölési funkció területe:
BF84: Az igényelt puffer típusa: 01=video
BF85: A puffert igénylő csatorna száma +1.
BF86-88: Az igénylő eszköz periféria-leírójának 24 bites címe.
BF89: A pufferigénylés jelzője: FF=nem volt még igénylés, 0=érvénytelen hívás (van már puffer).
BFBA: A legkisebb működő videoszegmens száma.
BF8B-8C: Utasításszöveg címe/puffer. A bővítő-letapogatás is használja.
BF8D-BE: A videocsatornák által elfoglalt RAM utolsó bájtjának Nick címe.
BF8F-90: A felhasználói határ értéke. (osztott szegmensnél használt)
BF91-92: Az EXOS-határ értéke. (Csatornaterület vége)
BF93-94: A csatornaterület kezdőcíme. (Perifériaterület vége)
BF95-96: A periféria terület kezdőcíme. (ROM-ok RAM-területének vége)
BF97-98: A ROM-bővítők RAM-területének kezdőcíme. (ROM-lista vége)
BF99: A RAM-bővítőknek kiutalt szegmensek listájának első eleme.
BF9A-9B: Az EXOS határszegmens címe.
BF9C-9D: A ROM-bővítők listájának kezdőcíme. (RAM szegmens lista vége)
BF9E-A4: A rendszerállapotot leíró bájtok, ahogy azt a 14H kódú EXOS-funkció adja vissza.
BF9E: Az EXOS határszegmens száma. (0 ha nincs)
BF9F: A szabad szegmensek száma.
BFA0: A felhasználó részére kiutalt szegmensek száma.
BFA1: A perifériák és RAM-bővítők részére kiutalt szegmensek száma.
BFA2: A rendszer által használt szegmensek száma.
BFA3: A működő RAM-szegmensek száma.
BFA4: A nem működő RAM-szegmensek száma.
BFA5-B1: A három legutóbb használt csatorna kódja és leírójuk 24 bites címe, valamint egy lezáró 00 a BFB1 címen. A legalacsonyabb bájton a csatornakód eggyel megnövelt értéke áll, majd a cím és a szegmensszám. A csatornakezelő funkciók esetén az EXOS a BFA5 címtől kezdve végignézi ezt a táblát, hogy szerepel-e benne a keresett csatornakód. A tábla végét 00 csatornakód jelzi. Az EXOS próbálja lerövidíteni a keresést a láncban.
BFB2-83: 0
BFB4-B5: A csatorna-RAM területének kezdőcíme (egy eltolási érték a BFBD címhez képest).
BFB6-89: 0
BFBA-BC: A csatornaleíró lánc első elemének 24 bites címe.
BFBD-BF: Az eszközleíró lánc első elemének 24 bites címe. A pointer a leíró DD-TYPE mezéjére mutat.
BFC0-C2: A RAM-bővítő lánc első elemének 24 bites első lapú címe. A pointer a belépési pontra mutat.
BFC3-C4: A REM1 és REM2 rendszerváltozó állításakor használt segédrutin címét tartalmazza az 1. szegmensen értelmezve. A magnókezelő inicializáló rutinja E9C1-re állítja be. Az itt lévő rutin a megfelelő rendszerváltozó aktuális értékét beírja a PORTB5 rendszerváltozóba és a /WR0 (0B5H) portra.
BFC5-EC: Az EXOS 10H hívással kezelhető EXOS rendszerváltozók:
BFC5: 0 IRQ_ENABLE_STATE /b0=hang, b2=1 Hz, b4=video, b6=DAVE (NET)
BFC6: 1 FLAG_SOFT_IRQ /szoftver megszakítás (tényleges címe BFF2)
BFC7: 2 CODE_SOFT_IRQ /szoftver megszakítás kádja
BFC8: 3 DEF_TYPE / fájl kezelő (0=magnó, 1=diszk)
BFC9: 4 DEF_CHAN / alapértelmezésű csatorna
BFCA: 5 TIMER / 1 Hz visszaszámláló (0-nál szoftver megszakítás)
BFCB: 6 LOCK KEY / 0=normál, 1=CAPS, 2=SHIFT, 8=ALT
BFCC: 7 CLICK KEY / 0=billentyűhang
BFCD: 8 STOP_IRQ / 0=stopra szoftvermegszakítás
BFCE: 9 KEY_IRQ / 0=billentyű lenyomásra szoftvermegszakítás
BFCF: 10 RATE_KEY / billentyűismétlés 1 /50Hz
BFD0: 11 DELAY_KEY / várakozás az ismétlésig 1/50Hz
BFD1: 12 TAPE_SND / 0=magnóhang bekapcsolva
BFD2: 13 WATT_SND / 0=SOUND várakozik ha megtellek a puffer
BFD3: 14 MUTE_SND / 0=belső hangszóró bekapcsolva
BFD4: 15 BUF_SND / hangburkoló mérete fázisokban
BFD5: 16 BAUD_SER / soros vonal sebesség
BFD6: 17 FORM_SER / soros vonal formátum
BFD7: 18 A R_NET / hálózati cím (NET szám)
BFD8: 19 NET_IRQ / 0=hálózat híváskor szoftver megszakítás
BFD9: 20 CHAN_NET / hálózatra blokkot küldő csatorna száma
BFDA: 21 MACH_NET / feladó gép NET száma
BFDB: 22 MODE_VID / video üzemmód
BFDC: 23 COLOR_VID / video színmód
BFDD: 24 X_SIZ_VID / video X méret
BFDE: 25 Y_SIZ_VID / video Y méret
BFDF: 26 ST_FLAG / 0=van státuszsor
BFE0: 27 BORD_VID / keret színe
BFE1: 28 BIAS_VID / 8-15 palettaszínek felső 5 bitje
BFE2: 29 VID_EDIT / erre a csatornára ír az editor
BFE3: 30 KEY_EDIT / erről a csatornáról olvas az editor
BFE4: 31 BUF_EDIT / editorpuffer = BUF_EDIT*100H (max. 63)
BFE5: 32 FLG_EDIT / az editor olvasás jelzője
b7=szerkesztés nélküli azonnali olvasás
b6=az egész szöveg olvasása
b5=szövegszerkesztés ESC-ig
b4=nem soronként hanem bekezdésenként kell olvasni
b3=a bekezdésből csak a prompt utáni részt kell olvasni
b2=a sor auto törlése (nyomtatható karakternél)
BFE6: 33 SP_TAPE / 0=magnó gyorsmentés
BFE7: 34 PROTECT / 0=magnó másolásvédelem
BFE8: 35 LV TAPE / felvételi szint (0-1=20, 2=40, 3=80, 4=170, 5=375, 6-255=700mV)
BFE9: 36 REM1 / 0=1. távirányító bekapcsolva
BFEA: 37 REM2 / 0=2. távirányító bekapcsolva
BFEB: 38 SPRITE / b0-b1=külső SPRITE színprioritása
BFEC: 39 RANDOM_IRQ / megszakítás számláló
BFED-FF: Az EXOS általános rendszerváltozói:
BFED-EE: Felhasználói megszakítási rutin címe. 0=nincs ilyen igény.
BFEF: A bejelentkezési üzenet elnyomásának jelzője.
BFF0-F1: 16 bites másodpercszámláló.
BFF2: A szoftvermegszakítás indítása.
BFF3: A B5 kiviteli port aktuális értéke.
BFF4-F5: Az LPT elejének címe.
BFF6-F7: A státuszsor memória címe.
BFF8-F9: A felhasználói melegindítás címe.
BFFA-FB: A rendszerveremtár ellenőrzéséhez használt 16 bites érték.
BFFC: 0. lapregiszter.
BFFD: 1. lapregiszter.
BFFE: 2. lapregiszter.
BFFF: 3. lapregiszter.
HSoft & EGO - Enterpress 1994/5.
Kecskés Sándor (SASA) - Enterpress 1994/6
Billentyűzet és joystick olvasásBillentyűzet kiolvasási mátrix táblázat
(Assembler programozáshoz használható)
Használati utasítás képlete:
LD A,n | azt a sort írjuk "n" helyére amely sorban van a kiválasztott billentyű. (0-9) |
OUT (0B5H),A | kiküldjük a B5 portra a kiválasztott sort |
IN A,(0B5H) | beolvassuk a kiválasztott sor értékeit. |
AND N | "N" helyére azt a hexadecimális számot írjuk amely oszlopban a kiválasztott billentyű van. |
JR Z,N | Ha a kiválasztott billentyűt nyomtuk meg akkor a "Z" jelző billentyű 1-re billen és a feltétel teljesül. |
80H |
40H |
20H |
10H |
08H |
04H |
02H |
01H |
Példa:
|
|
SH. bal |
Z |
X |
V |
C |
B |
\ |
N |
0 | |
CTRL |
A |
S |
F |
D |
G |
LOCK |
H |
1 | |
TAB |
V |
E |
T |
R |
Y |
Q |
U |
2 | |
ESC |
2 |
3 |
5 |
4 |
6 |
1 |
7 |
3 | |
F1 |
F2 |
F7 |
F5 |
F6 |
F3 |
F8 |
F4 |
4 | |
ERASE |
^ |
0 |
- |
9 |
8 |
5 | |||
] |
: |
l |
; |
K |
J |
6 | |||
ALT |
ENTER |
JOY. bal |
STOP |
JOY. fel |
JOY. jobb |
JOY. fel |
HOLD |
7 | |
INS |
SPACE |
SH. jobb |
. |
/ |
, |
DEL |
M |
8 | |
[ |
p |
@ |
O |
I |
9 |
Billentyűzet és joystick olvasás
Billentyűzet olvasás: | Joystick olvasás: |
LD A,X OUT (0b5H),A IN A,(0B5H) BIT X,A JP Z,LENYOMVA |
LD A,X OUT (0B5H),A IN A,(0B6H) BIT 0,A JP Z,LENYOMVA |
X |
bit 7 |
bit 6 |
bit 5 |
bit 4 |
bit 3 |
bit 2 |
bit 1 |
bit 0 |
bit 0 |
0 |
Bal SH. |
Z |
X |
V |
C |
B |
\ |
N |
TŰZ J1 |
1 |
CTRL |
A |
S |
F |
D |
G |
LOCK |
H |
FEL |
2 |
TAB |
W |
E |
T |
R |
Y |
Q |
U |
LE |
3 |
ESC |
2 |
3 |
5 |
4 |
6 |
1 |
7 |
BAL |
4 |
F1 |
F2 |
F7 |
F5 |
F6 |
F3 |
F8 |
F4 |
JOBB |
5 |
ERASE |
^ |
0 |
- |
9 |
8 |
TŰZ J2 |
||
6 |
] |
: |
L |
; |
K |
J |
FEL |
||
7 |
ALT |
ENTER |
BAL |
HOLD |
FEL |
JOBB |
LE |
STOP |
LE |
8 |
INS |
SPACE |
jobb SH. |
. |
/ |
, |
DEL |
M |
BAL |
9 |
[ |
P |
@ |
0 |
I |
JOBB |
Ferenci József - Enterpress 1995/3-4.
B0-B7, BF regiszterek értelmezéseOUT (B0),A 0. lapregiszter írása |
IN A,(B0) 0. lapregiszter olvasás |
OUT (B1),A 1. lapregiszter írása |
IN A,(B1) 1. lapregiszter olvasás |
OUT (B2),A 2. lapregiszter írása |
IN A,(B2) 2. lapregiszter olvasás |
OUT (B3),A 3. lapregiszter írása |
IN A,(B3) 3. lapregiszter olvasás |
OUT (B4),A
|
IN A,(B4)
|
OUT (B5),A
|
IN A,(B5) |
OUT (B6),A |
IN A,(B6)
|
OUT (B7),A
|
|
OUT (BF),A
|
HSOFT - Enterpress 1995/3-4
A forráslista magyarázata:
A lefordított felhasználói program a négyből három megszakításforrást is használ. Felsorolva: videó, 1 Hz, programozható megszakítás. Az első kettő nem okoz nehézséget, mivel az EXOS perifériák már használják. Problémát okoz viszont a programozható megszakítás, ha nem az 1 KHz-et szeretnénk alkalmazni. A DAVE A0-AF portokat videómegszakításból a SOUND periféria, HOLD állapot alatt a KEYBOARD periféria is átírja. Ezért a SOUND perifériát letiltjuk egy azonos
nevű, de feladatot nem végző felhasználói periféria felvételével. A KEYBOARD-HOLD miatt videómegszakításból frissítjük a DAVE általunk használt 3 regiszterét. Az új megszakításforrást bevezetjük a 0. EXOS változóba, majd megadjuk a saját megszakításrutinunk címét. A csatornák megnyitása némi magyarázatot kíván. Az OPEN rutin után felsorolom a szükséges EXOS változók új értékét, a végét nullával jelzem. Utánuk megadom a csatornák számát és nevét, a végét 255-tel adom meg. (rövidebb mint a macro.) A PRINT rutin hasonló módon a hívó helyről olvassa be a paramétereket. Hossz, csatornaszám, sztring. Utána kirakjuk a képernyőre a videólapot. Megadjuk a szoftvermegszakítás kezelőnk címét. Ezt a megszakítást többnyire a perifériák generálják, de a felhasználói program is indíthatja az 1. EXOS változó írásával. (FF:BFF2) A STOP hatására tehát a KILEP rutin EXOS RESET-et hajt végre, (SOUND perifériánk törlése) kijavítja a karakterkészlet módosított szóközét, majd kilép BASIC-be. A főprogramot tovább követve, információt írunk a képernyőre majd olvassuk a billentyűzetcsatorna állapotát. Itt addig fogunk várakozni amíg érvényes karaktert nem kapunk.
Töröljük a képernyőt és meghívjuk az input rutint. A
kapott szöveget átadjuk az EXOS parancsértékelőjének, majd kezdjük elölről az egészet. (A magnós alaprendszer csak két parancsszót ismer WP, BASIC, valamint a HELP, HELP BASIC, HELP WP információ kérést.) Ezalatt a megszakításkezelőnk a
következőket végzi. Szelektálja a D-ben átadott forrást és meghívja a megfelelő megszakításkezelő alrutint. Másodpercenként felcseréli a videólapunk papír és
tintaszínét. 50 Hz-el frissíti a programozható megszakításunk alapértékeit, kezdőértéket ad a keretszínnek, majd véletlenszerűen módosítja a karakterkészlet
szóköz definícióját 9 bájton. A programozható megszakításunkat 352 Hz-re adtuk meg, ilyenkor történik a keretszín növelése. Itt korlátot jelent az EXOS megszakítás kiszolgáló sebessége, ezért magasabb frekvenciákat csak az EXOS kihagyásával lehet alkalmazni. (pl. EPDOS 2.1 háttérnyomtatása 1 KHz-el)
Kiegészítés a megszakítás kezelés című cikkhez:
A Z80-nak két megszakítás kérő bemenete van. A nem maszkolható megszakítás NMI,
prioritásban erősebb a maszkolható megszakításnál INT. Létezik még CPU_RESET
bemenet is. A Z80 a megszakításkezeléshez két tárolót is használ. IFF=1 engedélyezi
a maszkolható megszakítást, míg IFF2 csak adatmentésre alkalmazott.
Az elfogadott NMI (CALL) a 66H címet hívja meg. Előtte a Z80 IFF1 megszakítás
engedélyező regiszterét nullázza, vagyis tiltja a maszkolható megszakítást.
Az elmentett IFF2 tesztelhető is. Értéke megjelenik az LD A,I vagy LD A,R utasítások
F-státuszában a paritásjelző biten. (P\V) Az NMI visszatérésére a RET helyett
RETN utasítás használható, mely helyreállítja az IFF1et. Az NMI-megszakítást
az ENTERPRISE gépben nem használják.
Az INT megszakítás 3 féle lehet, melyek beállítására az IM1, IM2, IM3 utasítás
szolgál. A RESET a nullás módot állítja be. Az elfogadás törli az IFF1-IFF2-t.
MODE 0: Az adatsínről olvassa be a végrehajtandó utasítást (többnyire RST) vagy
az esetleges hosszabb hívást (pl. CALL bájtbájt)
MODE 1: Automatikusan végrehajtja az RST 38H utasítást.
MODE 2: Az adatsínről beolvassa a megszakításvektor alacsony bájtját (páros
érték). A magas bájtot az l-regiszter adja, melynek értékét az előzetesen kiadott
LD I,A utasítás állította be. Erről a címről beolvasott 16 bites érték adja
a megszakítás-kezelő tényleges címét, melyet CALL utasítással fog meghívni.
A visszatérés RETI utasítással történik. A kiegészítő áramkörök ennek kódját
közvetlenül az adatsínen felismerik és oldják a prioritási láncot.
Az ENTERPRISE az IM1-et használja. Az IM2 nem alkalmas erre a gépre, mivel hiányoznak
a kiszolgáló áramkörök. A beolvasott megszakításvektor többnyire FF, így I=00
esetén a 00FF címről kapná a megszakításkezelő címet.
HSOFT - Enterpress 1995/3-4
Az Enterprise memórialapjainak kezelése
Az EP-ben Z80-as processzor dobog, mely a memóriát 16 biten címzi meg ami csak 64 kilobyte tartományt eredményez. A Z80 illesztését a DAVE-vel oldották meg, mely a következő feladatokat végzi:
Az EP 22 bites tárat tud kezelni, ami 4 Megabyte tartománynak felel meg. A címzés a Z80 és a DAVE tartalmától függ. Az alsó 14 bitet a Z80, a felső 8-at pedig a DAVE generálja az alábbi módon. 4 írható-olvasható lapregisztere van, melyben 8 bites értékeket tárol. A Z80 2 felső bitje megcímzi a lapregiszterek egyikét és a benne tárolt értéket küldi ki helyette.
Az ábrából kitűnik, hogy az EP 64 K-s Z80-ja 4 Megát tud címezni. Ehhez viszont időnként módosítani kell a DAVE lapregiszter tartalmát. Ezt lapozásnak nevezzük.
Miért kell lapozni? Mert a memória meghaladja a Z80 által kezelhető 64 kilobyte-ot. Amikor egy könyvet olvasunk, 2 oldalt láthatunk egy időben. A többit lapozással érhetjük el. Az EP-nek 4 lapja van, egyenként 14 bites, azaz 16 kilobyte memória kapacitással. Bármely lapra, bármely szegmens belapozható, így akár mind a 4 lapra belapozható ugyanaz a szegmens.
A szegmensek száma 256, ebből a valóságban keveset használunk. A gép bővítésével számuk növelhető. A memória 2 féle lehet. Csak olvasható ROM, írható és olvasható RAM. A ROM-memória kikapcsolás után is megőrzi a tartalmát. Hiányában elképzelhetetlen a hidegindítás. A ROM-okon nem csak az operációs rendszer rezidens részét tárolhatjuk, hanem tetszőleges bővítéseket, programokat és adatokat.
Egyszerűbb vezérlési rendszerek akár csak ROM kiépítésű memóriával is működhetnek. A bonyolultabb feladatokhoz, ilyen pl. a képernyő kezelés, már elengedhetetlen a RAM memória. Az EP operációs rendszere szintén megköveteli a minimum 2 szegmensnyi RAM-ot.
Mit, mikor, hova lapozzunk? Az alapkiépítésű EP a következő memóriaszegmenseket tartalmazza:
A NICK videó chip a Z80-tól független módon kezeli a képernyőt, és a 64 K-s videó RAM-ot a NICK prioritásban elsődlegesen tudja olvasni. A címei úgy alakulnak, mintha FC FD FE FF szegmenseket lapoznánk be a Z80-nak. A valóságban ilyen belapozással nem futtatunk programot, ezért a videó RAM egy-egy szegmensét belapozzuk valamelyik lapra és átszámoljuk a NICK címét Z80 címre, vagyis a 16 bites érték 2 felső bitjét módosítjuk. Az EP hidegindítás és RESET utáni környezete: A NICK 4 regiszterének értéke 0. Ezek a FIXBIAS, BORDER, LPL, LPH. A DAVE 16 hang regisztere, 4 lapregisztere, 1 megszakítás regisztere, 3 I/O regisztere, 1 memória elérést szabályzó regisztere szintén 0. A Z80 PC-regisztere szintén 0. Ebből kiindulva tehát mind a 4 lapon a nullás szegmens látható. A Z80 az induló kódot tehát a nullás lap 0000 címéről olvassa, melyen a nullás ROM szegmens van belapozva. A megszakítás tiltott állapotban van. IM 1-re kapcsol, majd elugrik a 3. lapra ahol szintén a nullás romszegmens látható. A 4. szegmenset a nullás lapra lapozva ellenőrzi a "TEST_ROM" kezdést. Ha ilyet talál, átadja neki a vezérlést 0008 címen. Így működnek a gyorstesztes bővítések. Tovább futva ellenőrzi a melegindítási mód lehetőségét. Ez annyit jelent, hogy némi inicializálás után visszaadja a vezérlést az aktuálisan futó felhasználói programnak. Tovább futva megkezdődik a hidegindítás. RAM teszt, illetve a RAM szegmensek listába vétele.
Ekkor már kialakul az operációs rendszer lapkiosztása. A nulladik lapon a legalacsonyabb értékű RAM-szegmens található, melynek értéke alap gép esetén F8. Ide másolódik 0030-005A közötti területre az operációs rendszer nulláslapú rutinjai. Az RST 30 az EXOS funkcióhívásokat, az RST 38 pedig a megszakításokat szolgálják. Ezt a nulláslapot tehát nem szabad soha elállítani, kivéve úgy, hogy tiltott megszakítás mellett ellapozzuk majd helyreállítjuk! Az első lap tartalma virtuális, ez a munkaszegmens. A második lapra az FF RAM-szegmens, vagyis a rendszerszegmens kerül. Itt van kiépítve az operációs rendszer veremtára, tehát ki lapozás alatt gondoskodni kell arról, hogy ne történjen megszakítás, illetve ne legyen vermet igénylő művelet. A harmadik lapon a nullás ROM-szegmens marad.
A továbbiakban történik a ROM-szegmensek könyvtárba vétele, ROM-ok RAM igényének kiszolgálása, alapperifériák könyvtárba vétele és inicializálása, majd a ROM-bővítők inicializálása. Ezt követi a bejelentkezés, mely le is tiltható. Utána a hidegindítás akciókóddal megtörténik a bővítők letapogatása. Amikor egyetlen bővítő sem igényli, akkor a 01-es ROM szegmens elfogadja és elindítja a WP felhasználói programot.
Az operációs rendszer alatt két féle program futtatható: Felhasználói és rendszerbővítő. Mindkét program létrehozhat felhasználói periféria bővítést, mely leegyszerűsítve harmadik lapon futó rutinkönyvtár, belépési táblázattal.
Az EP alatt minden esetben egyetlen felhasználói program futhat. E programból EXOS-hívás vagy megszakítás által meghívható az operációs rendszer. Az operációs rendszer tovább hívhatja a bővítőket és perifériákat. Ebből következik, hogy legnagyobb szabadsággal a felhasználói program rendelkezik. A nullás laptól eltekintve a szegmenseket szabadon lapozhatja. Veremtárát a harmadik lap kivételével bárhol kialakíthatja. Felhasználói RAM memóriát igényelhet vagy szabadíthat fel az operációs rendszeren keresztül. Amikor egy másik felhasználói program veszi át az irányítást, akkor az operációs rendszer feladata a memória, perifériák és bővítések inicializálása. Felhasználói futást kétféleképpen lehet kialakítani. Fájl-típusú vagy bővítésből indított. Fájl-típus: A fejléc 00, 05-tel kezdődik. Ezt követi a két bájtos betöltési méret. A rendszer betöltési rutinja nem teljesen korrekt. 0100-7FFF-ig hibátlan. 0100-BFFF-ig töltve a szegmenseket nem lapozza be, tehát ki kell talál ni. Ezért azt javaslom, hogy a 7FFF-et ne haladja meg az 5-ös fejlécű programfájl. A további adatokat a program is beolvashatja egy másik fájlról. A betöltő 5-ös fejlécű programnál felszabadítja a felhasználó által foglalt memóriát, lefoglalja a betöltéshez szükséges memóriát, majd végrehajtja a betöltést. Töltési hiba esetén hibaüzenetet küld az alapértelmezésű csatornára, majd hidegindítás akciókóddal meghívja a bővítőket. Hibátlan töltésnél inicializálja a perifériákat és bővítőket, felhasználói futásra kapcsolja a rendszert és 0100-tól elindítja a programot. Újabb hibája hogy a megszakítást nem tiltja, pedig a felhasználói program még nem építette ki a veremtárát. Első lépés tehát az LD SP,? vagy a DI programsor legyen!
Kis veremigényű programoknál bevált szokás az LD SP, 100H utasítás.
A lapok kiosztása ebben az esetben:
Bővítőből indított felhasználói futás: hidegindítás akciókód elfogadása esetén a teendők.
LD C,0
EXOS 0
LD SP,?
EI
Parancs sztringgel indított felhasználói futásnál a felismerés utáni ág:
LD C,60H
EXOS 0
LD SP,?
EI
A felhasználói program lépései a továbbiakban:
LD A,255
OUT (0B2H),A
LD HL, inter
LD (0BFEDH),HL
LD HL, softint
LD (3DH),HL
LD A,255
OUT (0B2H),A
LD HL,melegstart
LD (0BFFRH),HL
A felhasználói program nem fejezheti be a futását mint egy bővítő rutin.
Kilépési lehetőségek:
LD DE,BASIC vagy WP stb.
EXOS 26
JP HIBA ;nem ismeri fel a sztringet a rendszer
BASIC: DB 5,"BASIC"
WP: DB 2,"WP"
ISMETLD A,255
OUT (0B2H),A
XOR A
LD (0BF78H),A
EXOS 26
JR ISMET
LD C,80H
EXOS 0
A bővítő rutinja visszatérés előtt a nullás és második lapot állítsa helyre. Vigyázz a lapozásoknál mivel:
Javasolt könyv:
az EXOS 2.1 Változat Műszaki Leírása
Haluska László
(Az 1999-es Enterpress News tervezett 1. számából)
EXOS kompatibilis memóriakezelés
Az ENTERPRISE a maga korában, sőt talán a 8 bites gépek történetében nézve összességében is egyedülálló módon rugalmasan bővíthetőre lett megtervezve, így például a maximálisan kezelhető memória méret az akkoriban szinte elképzelhetetlen 4 megabájtban lett meghatározva. Mindez ráadásul nagyon tisztán, áttekinthetően lett megoldva: a Z80 64K-s címtartományát felosztjuk 4 db 16K-s lapra, a 4 megabájtot pedig 256 db 16K-s szegmensre. És bármelyik szegmenst belapozhatjuk bármelyik lapra, sőt még azt is megtudhatjuk, hogy melyik lapra melyik szegmens lett belapozva.
Sok más gépen csak irigykedni lehet egy ilyen egyszerűen használható rendszerre, majd egyszer - a Spectrum programok átírása kapcsán - részletezem, hogy milyen "barkácsolással" lett a Spectrum 48-ból 128-as gép, ill. milyen további ronda barkácsolásokkal érték el az oroszok a 256K esetleg 1 mega memória használatát... De a szocialista kistestvér, azaz a TVC esetén is jelentősen lebutítva és egyben bonyolítva lett a rendszer, csak, hogy pár logikai kaput megspóroljanak...
Persze a hardware lehetőség kevés, kell mindehhez egy olyan operációs rendszer, ami mindezt tudja kezelni, kihasználni. Szerencsére mi egy igazán remek rendszert kaptunk, amely teljességgel rászolgált az Enterprise eXtendable Operating System névre! Az EXOS feladata az aktuális konfiguráció felderítése, a használható memória leltárba vétele, majd pedig a felhasználói programok ill. különböző rendszer összetevők által támasztott memória igények kiszolgálása, nyilvántartás vezetése az aktuálisan foglalt ill. szabad memória területekről. Akárcsak egy mai modern operációs rendszer esetén!
A kortárs gépeken nem is igazán lehet operációs rendszerről beszélni, memóriakezelés is gyakorlatilag csak a BASIC interpreteren belül létezik, változók stb. nyilvántartása. Így például egy Spectrum program se tudhatja meg rendszerszinten, hogy 48-as, 128-as vagy netán egy orosz Scorpion 256-os gépen fut. Itt ha nem érdekel minket a BASIC, gyakorlatilag nincs semmi más amire figyelni kellene, ráadásul minden fix, és változatlan, a képernyő-memória is teljesen rögzített helyen van, semmi akadálya a "POKE-PEEK" stílusú programozásnak.
Enterprise esetén egyrészt alapból is több többé-kevésbé különböző géptípus került kiadásra (64, 128, EXOS 2.0 és 2.1, angol és német), másrészt a különböző bővítésekkel számtalanra növekedett a különböző létező konfigurációk száma.
Sajnos a cég sikertelensége azzal is járt, hogy nem volt hivatalos támogatás, oktatás, cikkek, könyvek, arra vonatkozóan, hogy ezt a kitűnő rendszert hogyan is kell helyesen kihasználni, hogyan kell megfelelően programozni. Így a géppel foglalkozó programozók leginkább a más gépeken megszokott fix környezetet használó stílust vették át, az elérhető dokumentációkból csak annyit hasznosítva, hogy egyes fix(nek) gondolt pontokat megkeressék. Ez nálunk különösen jellemző volt, egyrészt mivel a legjobban eltérő EP64-es nálunk nem került forgalomba, másrészt a hivatalos dokumentációk is csak késve és nem túl jó minőségben fordítva jelentek meg. Ráadásul a megjelent könyvek, cikkek nagy része is ezt a fix memória konfigurációs "POKE-PEEK" stílust hirdette.
Milyen problémák adódnak ebből? Anno a hírhedt angol-német gépek közötti inkompatibilitás, mind ennek volt köszönhető. Ez különösen a BASIC-gépi kód keverék programokra volt jellemző. Ennek köszönhető sok összevissza barkácsolt, kapcsolóval megspékelt cartridge...
Ezek ugyan már át lettek bütykölve, de a dolog most fokozottan megismétlődik a winchester vezérlővel, hiszen itt még több terület lesz lefoglalva a rendszerszegmensben, és itt különösen nem egészséges, ha beleírunk a lefoglalt memóriába. Ennek akár nagyobb adatvesztés is lehet a vége!
A "Világ EP tulajdonosai egyesüljetek" mozgalmunk keretében került előtérbe az a probléma, hogy a létező EP programok kb. 98%-a nem fut EP64-en, annak ellenére, hogy jelentős részük fizikailag beférne a 64K-ba! És hiába vesz mondjuk egy MICROTEAM kártyát az EP64 tulajdonos, az így 576K-ra növelt memóriával se fog futni a 128-as programoknak még mindig vagy 96%-a... mivel az F8-FB szegmensek nem léteznek egy ilyen gépen. (Sajnos az ep128emu egyik hiányossága, hogy ilyen "lukas" memória konfigurációkat nem lehet emulálni, ezt csak EP32-ben lehet elkészíteni.)
F8-FB szegmensek megvalósítása után még mindig sok programnak gondot okozna az EXOS 2.0. És amire nem került sor, de hatalmas balhé lett volna: ha kijött volna a tervezett szuper EP az EXOS 3.0-val, várhatóan szintén rengeteg program nem működött volna vele...
Szintén lettek volna problémák, ha anno kiadják a winchester vezérlőt (amit az eladatlan SZJA 88 készletek miatt visszatartottak...)
Akkor menjünk bele a részletekbe, először egy kis összefoglaló:
Van 4MB címtartományunk, ez fel van osztva 256 db 16K-s szegmensre. Meglepő módon 0-255-ig számozzuk őket, hexában 00-FF. Alapvetően bármelyik lehet RAM vagy ROM vagy maradhat üresen, kivéve amit maga az alaplap határoz meg:
Ha a RAM-ot nézzük, egy 64K-s gépben van FC-FF. 128-asban F8-FF. Ha a korábban emlegetett MICROTEAM + EP64 konfigot nézzük, akkor pedig 40-5F, FC-FF, ami darabra bőven jó, csak hiányzik az a bizonyos F8-FB, amire az EXOS-t nem használó 128-as gépen programozók által írt programok nagy része hivatkozik közvetlenül. A helyes programozáshoz felejtsük is el ezeket a számokat, egyedül az FC-FF-et kell megjegyezni, kitüntetett videó memória mivoltuk miatt. A többiről csak annyit kell tudnunk, hogy nekünk hány darabra van szükségünk, a konkrét szegmensszámokat majd megmondja az EXOS!
Most nézzük az EXOS szerinti RAM felosztást: két szegmensnek van kitüntetett szerepe, az egyik az FF ami a rendszerszegmens, és a legalacsonyabb sorszámú RAM szegmens ami a nulláslap szegmens. Itt található meg az EXOS hívások, illetve a megszakítási program belépési pontja. És ide kerülnek 100H címtől töltve az 5-ös fejlécű programok is. Egy 128-as gépen az az F8 szegmens. De ha pl. van egy MICROTEAM kártyánk, akkor már a 40-es lesz az. És ez máris gondot okoz sok programnak (általában a komplett módosított Spectrum ROM-ot tartalmazó béna átiratoknak)... De bővítős gépen is lehet F8 a nulláslap, ha VENUS-t használunk, ill. az EPDOS 2.1-nek is van ilyen lehetősége. Ez az eset meg egy másik adag programnak okoz gondot...
A maradék RAM négy csoportba tartozhat: rendszer, eszköz, felhasználói, szabad. Ha pl. csatornákat nyitunk meg, különösen, ha nagy RAM igénnyel járó videó lapokat, akkor az EXOS elkezd lefelé terjeszkedni, és ha kihízza az FF szegmenst, akkor további szegmensek válhatnak rendszer által lefoglalttá.
A különböző beláncolt EXOS periféria kezelők által igényelt teljes RAM szegmensek az eszköz (device) kategóriában kerülnek lefoglalásra. Erre tipikus példa a RAMDISK. Szintén ebben a kategóriába kerülnek lefoglalásra a betöltött rendszerbővítők által elfoglalt szegmensek is.
És végül van az aktív felhasználói program, ez lehet egy rendszerbővítő vagy egy 5-ös fejléccel betöltött "új alkalmazói program". Az ezek által igényelt szegmensek a felhasználói kategóriában kerülnek lefoglalásra. Ami nagyon fontos: a felhasználói program csak felhasználói szegmenst tud felszabadítani, eszköz vagy rendszer szegmens felszabadításához nincs joga!
És ezzel el is érkeztünk ahhoz a bizonyos Spectrum Világ-os hibás módszerhez:
LD C,0FAH
EXOS 25
LD A,0FAH
OUT (0B2H),A
Egyrészt a szándék dicséretes, hiszen nem csak bumm belapozza a szegmenst, hanem szabaddá teszi... csak sajnos a nem túl sikeres fordítású EXOS leírást félreértelmezve. Mert az EXOS 25 hívás csak akkor lesz sikeres, ha előtte az a szegmens nekünk, azaz felhasználóiként ki lett utalva. Ha az FAH már mondjuk a RAMDISK része, vagy egy betöltött EXOS bővítő van ott, akkor mivel eszköz szegmensnek van lefoglalva, hibajelzést kapunk vissza, hogy a szegmens nem szabadítható fel. A program viszont ennek ellenére nyugodtan neki áll használni. És ott van még az a eset is, hogy nem is létezik ez a szegmens az adott konfigurációban, mert pl. EP64-ről van szó...
A helyes megoldás itt az, hogy kérünk kiutalni egy szegmenst az EXOS-tól, és azt használjuk. Ha hibajelzést kapunk vissza, mert elfogyott a szabad memória, akkor azt a programtól függő módon le kell kezelni (pl. kilépés, vagy lehet folytatni korlátozott funkcionalitással a program futását).
EXOS 24
JP NZ,HIBA
LD A,C
OUT (0B2H),A
Kicsit macerásabb, ha egy konkrét számú szegmensre vágyunk: ekkor ciklusban kell ismételgetni az EXOS 24 hívást, mindaddig, amíg meg nem kapjuk a kívánt szegmenst, vagy pedig elfogy a memória, és ekkor megyünk a HIBA rutinra. De erre a módszerre új program írása esetén csak egy esetben lehet szükség: ha videó szegmensre van szükség. Ekkor addig ismételjük a hívást ameddig FC vagy nagyobb szegmenst nem kapunk.
És akkor kell még ehhez a módszerhez folyamodni, ha egy régebbi fix címzéses programot akarunk kibővíteni úgy, hogy amit a program használ, az legyen szabályosan lefoglalva, mint ahogy ezt tettem a TUSKER-rel.
Ez volt Attus eredeti rutinja, amely az SpV módszeren alapult:
SZABADLD BC,5FAH
PUSH BC
EXOS 25
POP BC
INC C
DJNZ SZABAD
Ebből kiderül, hogy az FA-tól kell nekünk 5 szegmens, illetve később kiderült, hogy az LPT táblát az FF szegmens elejére helyezi el.
És íme mindez helyesen:
FOGLAL
EZKELL
VISSZAADEXOS 24
JP NZ,HIBA
LA A,C
CP 0F9H
JR NZ,FOGLAL
LD BC,5FAH
PUSH BC
EXOS 24
LD A,C
POP BC
CP C
JP NZ,HIBA
INC C
DJNZ EZKELL
EXOS 24
CP 7FH
JP NZ,HIBA
LD DE,3200
EXOS 23
JP NZ,HIBA
LD L,0F9H
LD C,L
EXOS 25
DEC L
JR NZ,VISSZAAD
Az elején addig foglalunk, amíg az F9-ig el nem jutunk. Ha közben kifogyunk a memóriából, akkor ugrás a HIBA-ra. Ezután kérünk még 5 szegmenst, aminek FA,FB,FC,FD,FE-nek kell lennie, különben HIBA... És még egyet igényelünk, itt már csak az FF jöhet, és "megosztott szegmens" hibajelzést kell kapnunk (ez a 7F hibakód), különben hiba.
És itt jön még egy fontos dolog: megosztott szegmens használata esetén meg kell mondanunk az EXOS-nak, hogy mi meddig akarunk terjeszkedni, erre szolgál az EXOS 23: felhasználói határ beállítása. Ha itt hibajelzést kapunk, akkor nincs annyi szabad hely amennyire nekünk szükségünk van, tehát ugrás a HIBA-ra.
Ha minden ok, akkor egy nem túl szép, nem túl gyors, de egyszerű módszerrel visszaadjuk a felesleges szegmenseket. Vagyis F9-től lefelé mindet megpróbáljuk felszabadítani, úgyis csak az fog sikerülni amit felhasználónak utaltak ki. A teljesen korrekt megoldás természetesen az, ha az elején eltároljuk sorban a kapott felesleges szegmenseket, és ezen lista alapján szabadítunk itt fel. Erre akkor van szükség, ha az 5-ös fejlécű programunk már nem fér el a nulláslapon, mert ekkor a további programszegmensek is felhasználóiként kerülnek lefoglalásra, és ezzel a primitív módszerrel azokat is felszabadítanánk, pedig azt
nem lenne szabad. A TUSKER betöltő esetén nincs ilyen gond, jó így is.
Jogosan merülhet fel a kérdés: Konkrét szegmens igénylésére nincsen valami elegánsabb módszer? Mert így szélsőséges esetben akár 249 szegmenst is lefoglalhatunk magunknak, míg végre megkapjuk pl. a hőn áhított FC (video) szegmensünket. És akkor ezután még fel kell szabadítani a fölöslegesen lefoglalt szegmenseket is, hátha kellenek még azok valamire...
Sajnos nincs... Ez egy pici hiányosság az EXOS-ban. Jó lenne ha külön lehetne jelezni, hogy videó szegmenst szeretnénk kérni. Erre egyedül a periféria kezelő programon keresztül van lehetőség, ha videó periféria típust állítunk be. Így jobb híján marad ez a ciklusos megoldás. Lehetséges még közvetlenül az EXOS rendszerterületeiben matatni, ezt több könyvben, cikkben tárgyalták is. De az ilyen programok máris elszállnak EXOS 2.0 esetén... esetleg meg lehetne írni külön két szubrutint EXOS 2.0 ill. 2.1 esetére. De mi van ha"véletlenül" készül újabb EXOS verzió? Azon megint csak nem fognak futni az ilyen "kotorászós" programok... Szóval szerintem jobb maradni a szabályos megoldásnál, az a pár tizedmásodperc futásidő amibe legrosszabb esetén kerülhet, nem egy nagy veszteség a kompatibilitás oltárán.
Ez volt a fix szegmensek használata szabályosan című fejezet.
Ott tartunk, hogy szeretnénk megszabadulni a fix szegmensszámoktól, ily módon a különböző konfigurációkhoz maximálisan alkalmazkodó programot írni. Nézzük mi a teendő ha memóriára van szükségünk?
Kezdetnek ott van a korábban emlegetett nulláslap. Ebből az EXOS a 0030-005BH területet használja, ill. az 5-ös fejlécű program ide kerül betöltésre 0100H címtől. A többi szabadon felhasználható az éppen aktív felhasználói program számára. Mint korábban már említettem, a nulláslap szegmensszáma különböző lehet a különböző konfigurációkban, az aktuális számot megtudhatjuk a B0H portról beolvasva, ill. a BFFCH címen lévő EXOS rendszerváltozó is tartalmazza (a rendszerváltózók címe úgy érvényes, ha az FFH rendszerszegmens a 2. lapra van lapozva). Ez később még fontos lesz, amikor majd kicsit trükközünk a nulláslappal), de alapesetben nem szokás piszkálni.
Nézzük tovább, mi van ha a nulláslap már nem elég, vagy nem felel meg az igényeinknek?
Nagyon egyszerű, kérünk további szegmenseket az EXOS-tól. Mivel már nem ragaszkodunk a fix szegmensszámokhoz, sokkal egyszerűbb a dolog, minden amit kapunk, az jó nekünk! Célszerű a kapott szegmensek számát eltárolni, későbbi lapozási műveletekhez nem árt tudni melyik szegmensekről van szó, ill. majd kilépéskor fel kell szabadítanunk ezeket.
Egy lehetséges módszer, például foglaljunk le 4 szegmenst:
FOGLALLD HL,RAMLISTA
LD A,4
EX AF,AF'
EXOS 24
JZ NZ,HIBA
LD (HL),C
INC HL
EX AF,AF'
DEC A
JR NZ,FOGLAL
Később pedig pl a 3. szegmensre így hivatkozhatunk:
LD A,(RAMLISTA+2)
OUT (0B3H),A
Itt megemlítem azt is, hogy a Spectrum Világ cikksorozatának az elején, amikor a Spectrum kazetta beolvasó programot tárgyalják, még a helyes memóriakezelésről van szó:
"EXOS 24 - Szegmens kijelölés. Memóriát célszerű az EXOS-tól kérni, mivel így biztosan nem kezd el más program is az általunk használni kívánt memóriában dolgozni. C regiszterben a kiutalt szegmens száma lesz. Programunk 3 db szegmenst foglal le, ez 48k, így minden SPECTRUM program belefér a tárba".
EXOS 24
LD A,C
OUT (0B1H),A
EXOS 24
LD A,C
OUT (0B2H),A
EXOS 24
OUT (0B3H),A; Egy 16 kbyte méretű RAM szegmens
; lefoglalása
; és belapozása
; az 1. lapra (4000H-7FFFH címtartomány)
; Még két szegmens lefoglalása
; és belapozása.
; Ezekre fog töltődni a program.
Kimaradt a hibakezelés, így kevés memória esetén, hiába szól az EXOS, hogy elfogyott, a program nem veszi észre, és hibásan fog működni.
Ezzel a sima szegmens igényléses módszerrel már remekül el lehet lenni, ha nincs szükségünk képernyő kezelésre, ill. ha megoldjuk az EXOS videó kezelőjén keresztül. Ha viszont magunk akarjuk a képet létrehozni, saját LPT táblával, ahhoz saját videó szegmens(ek)re lesz szükségünk! Itt kezdődnek a bonyodalmak...
Mi is a bonyodalom a videó szegmensekkel? Az egyik már felmerült kérdésként: nem tudunk közvetlenül videószegmenst igényelni, így kénytelenek vagyunk a már megismert ciklusos igényelgetéses módszerhez folyamodni.
"míg végre megkapjuk pl. a hőn áhított FC szegmensünket"
Ez viszont megint helytelen hozzáállás. Mert áhítozhatunk rá, de EP64-en nem fogjuk megkapni, mivel az csücsül a nulláslapon. Tehát a helyes hozzáállás az, hogy FC vagy nagyobb ami elfogadható. Jól eltesszük ennek is a számát, hol itt a gond? Az, hogy lesz itt még egy kis pluszmunkánk!
Általános célú szegmenseknél teljesen mindegy, hogy melyiket is kaptuk meg. Videó szegmens esetén ez már nem teljesen igaz! A miérthez nézzük meg a Nick chip memória kezelését, amiről eddig még nem volt szó: Azt már tudjuk, hogy az alaplapi 64K egyben a videómemória is. Ezt a Nick saját maga is címzi, az általa használ címeket nevezzük videócímeknek. Természetesen ezek is 0000-FFFFH tartományban lehetnek. De ezek a címek teljesen függetlenek a Z80 címeitől! A 0000-3FFFH tartomány jelenti az FCH szegmenst, 4000-7FFFH az FDH, 8000-BFFFH az FEH, C000-FFFFH az FFH. És ezek függetlenek attól, hogy a kérdéses szegmensek a Z80 számára hova vannak lapozva, vagy hogy egyáltalán be vannak-e lapozva.
Így amikor a videómemóriával végzünk műveleteket, szükséges lehet azt a címet amivel a Z80 érte el a kérdéses területet átszámolni videócímre a Nick számára. És van még egy számolgatás, amire akkor van szükség amikor az LPT tábla címét adjuk meg a Nick chipnek, mivel itt csak 12 bitet adunk át. Ezt legegyszerűbben úgy lehet megspórolni, ha a 0000H videócímre tesszük az LPT táblát, vagyis az FC szegmens elejére, ahogy teszi ezt pl. az SpV féle Spectrum átírat betöltő is.
Az LPT táblában pedig meg kell adnunk a képernyőadatok videócímét is. Az egyszerűség kedvéért az említett betöltő erre a célra az FD szegmenst használja, így 4000H videócímtől fog kezdődni a képernyő, ezt a kezdőcímet használja fixen az LPT generáló rutin. Nekünk viszont pont az a célunk, hogy a fix szegmensz számoktól megszabaduljunk!
Az említett Spectrum képernyő előállításához két videószegmensre lesz szükségünk, egy kell az LPT táblának, egy pedig a Spectrum képernyőnek, ami egyben a Spectrumos memória első 16K-ja is lesz. Mivel az LPT tábla nem tölt ki egy teljes szegmenst (szokásos Spectrum LPT tábla 3200 bájt), így ezt akár megosztott szegmensben is el lehet helyezni. Ezért a célszerű folyamat az, hogy az ismert módszer szerint addig igényelgetünk szegmenseket, amíg egy videószegmenst nem kapunk, ezt eltesszük képernyőnek, a következőt pedig LPT-nek. Ha fordítva csinálnánk, akkor előfordulhatna, hogy a nem teljes szegmensnyi LPT tábla kap egy teljes szegmenst, a teljes szegmenst igénylő videómemória pedig lehet, hogy márt csak megosztottat kap, ami hibához vezet...
128-as gépen ezzel pont fordított konfguráció jön létre, mint az SpV betöltőben: az FCH lesz a videószegmens, míg az FDH az LPT szegmens. Ezzel az eredeti Spectrum LPT építő rutin máris működésképtelenné vált, módosítani kell.
Hogyan számoljuk a videócímeket:
Kelleni fog a Z80-as cím, ill. a szegmensszám. A Z80-as címből a legfelső két bitet "dobjuk ki", és helyére a szegmensszám alsó két bitjét kell betenni. Amikor pedig az LPT címét mondjuk meg a Nick-nek, akkor az alsó 4 bitet kell "eldobni".
Folytassuk cikkünket gyakorlatiasabb részekkel!
Én ezt a rutint használom a Spectrum átirat betöltőimben videó szegmens igénylésre:
VID
KER
NAMIVAN
NEMKER
VISSZALD HL,VEGE
LD (HL),0
EXOS 24
JR Z,NAMIVAN
CP 7FH
JP NZ,HIBA
EX AF,AF'
LD A,C
CP 0FCH
JR NC,NEMKER
INC HL
LD (HL),C
JR KER
EX AF,AF'
PUSH BC
PUSH AF
LD C,(HL)
EXOS 25
DEC HL
JR Z,VISSZA
POP AF
POP BC
OR A
RET
A rutin a VEGE címtől (amely logikusan a programkód után helyezkedik el) tárolja el a felesleges szegmenseket. Miután akadt egy (amely lehet megosztott is), a felesleget visszaadja az EXOS-nak. Először a képernyőnek kérünk egy teljes szegmenst:
CALL VID
JP NZ,HIBA
LD A,C
CP 255
JP Z,HIBA
LD (VIDS),A
LD DE,0
RRA
RR D
RRA
RR D
LD (VIDCIM1),DE
A kapott szegmensszámból kiszámoljuk a terület kezdetének címét, erre később az LPT generáláskor szükség lesz.
Később kérünk egy LPT szegmenst is, ami lehet megosztott is, ha elfér benne az LPT tábla (azaz az EXOS határ
beállítható a megfelelő helyre.)
NEMHIBA
NEMHIBA1CALL VID
JR Z,NEMHIBA
CP 7FH
JP NZ,HIBA
LD DE,200*16
EXOS 23
JP NZ,HIBA
LD C,255
LD A,C
LD (LPTS),A
LD DE,(VIDCIM2)
LD HL,0
RRA
RR H
RRA
RR H
ADD HL,DE
LD (VIDCIM2),HL
Itt is kiszámoljuk a videó címet, ezúttal az LPT tábla kezdetét. A figyelmes szemlélő észreveheti, hogy itt még
játékba áll a VIDCIM2-n korábban lévő érték. Ez alapban nulla, viszont 64K-s gépen úgy fog átrendeződni a memória, hogy nem a szegmens elejére kerül az LPT tábla, ekkor a szükséges eltolás mértéke került már ekkora a VIDCIM2-re.
Ezekután nézzük meg, hogyan változik a SpV-ban is közölt LPT generáló rutin! Íme az eredeti rutin kezdete:
LD A,0FCH
OUT (0B1H),A
LD A,192
LD DE,4000H
EXX
LD DE,4000H
LD HL,4004H
LD BC,13
És ez lesz belőle:
LD A,(LPTS)
OUT (0B1H),A
LD A,192
LD DE,(VIDCIM2)
RES 7,D
SET 6,D
EXX
LD DE,(VIDCIM1)
LD IX,VIDCIM1
LD HL,(VIDCIM2)
RES 7,H
SET 6,H
INC HL
INC HL
INC HL
INC HL
LD BC,13
A fix szegmensszám helyett az eltároltat használjuk. A DE fog mutatni az LPT elejére az 1-es lapon, de a korábban említett esetleges eltolás miatt ezt az LPT videócíméből számoljuk vissza 1-es lapi címre. Az EXX utáni DE a videómemóriánk kezdetére fog mutatni, ez az eredeti rutinban fix 4000H volt, mivel az FDH volt fixen erre a célra használva. A HL pedig szintén az LPT területre fog mutatni, 4 bájt eltolással, ő az LPT sorokba való címbeírásnál van használva.
Nem esett még szó az IX-ről. Ő a videó memóriánk címét tároló változóra mutat. Azért mert, még egy helyen hozzá kellett nyúlni az eredeti rutinhoz, még pedig az attributum címek kiszámolásánál:
LD A,D
RRA
RRA
RRA
AND 3
OR 58H
LD (HL),A
Módosítva:
LD A,D
RRA
RRA
RRA
AND 3
OR 18H
OR (IX+1)
LD (HL),A
Ezekután már csak az LPT aktiváló OUT utasításokat kell módosítani, az eredeti nagyon egyszerű, mivel a fix 0000H videó címet használja:
XOR A
OUT (82H),A
LD A,192
OUT (83H),A
És módosítva, hogy a kiszámolt LPT címünket használja:
XOR A
LD HL,VIDCIM2+1
RRD
RLCA
RLCA
RLCA
RLCA
OUT (82H),A
OR 0C0H
RRD
OUT (83H),A
Megjegyzés, ez a módszer elrontja a VIDCIM2 változó értékét, de erre az adott esetben úgysincs többé szükség. De itt egy másik módszer is, itt az eredeti EXOS LPT visszaállítására van használva:
FORG4LD HL,(0BFF4H)
SET 6,H
LD B,4
SRL H
RR L
DJNZ FORG4
LD A,L
OUT (82H),A
LD A,H
OR 0C0H
OUT (83H),A
A címet az EXOS LP_POINTER változójából olvassuk ki (tehát legyen belapozva a rendszerszegmens a 2. lapra), az utána következo SET 6 azért van, hogy videócímre konvertáljuk az EXOS változót, ha saját kiszámolt videócímünket használjuk, akkor erre nincs szükség.
ZozoSoft