Spectrum Programok átírása


Általános áttekintés
Módosítás hardware oldalról
Hasznos tanácsok
A kód átvitele
A képernyő
A betöltő rutin
Megszakítás
Billentyűzetfigyelés
ROM hívások
Botkormány
Színkonverzió
128K-s programok

Zozosoft instrukciói a ZX Spectrum programok átírásáról
István instrukciói a 128K-s hangok átírásáról


Scan, OCR: gafz, 2006

Az ENTERPRISE gép piacra kerülésekor, és azóta is nagy probléma a programok hiánya (akár játék-, akár felhasználói programról is legyen szó). Ezzel szemben ott van pl. a SPECTRUM, amely a maga néhány ezer (!) software termékével a viszonylag jól ellátott gépek közé tartozik. Előbb-utóbb mindenkiben felvetődik a kérdés: hogy lehet a SPECTRUM programokat futtatni az ENTERPRISE gépen?

A futtatásra több módszer is lehetséges

Mi a most induló módszertani segédletben a második módszerrel szeretnénk foglalkodni, hasznos tanácsokat adva a kedves Olvasónak, azoknak akik elég önbizalommal (és tudással) rendelkeznek ahhoz, hogy egyénileg nekivágjanak egy ilyen mélységű munkának.

Általános áttekintés

Mindenekelőtt azt kell tisztáznunk, hogy mi szükséges egy valamely gépen futó program másik gépre történő átkonvertálásához:

  1. A program kódját át kell vinnünk az ENTERPRISE gépre.
  2. Az átvitt kódot hardware szempontból módosítanunk kell.
  3. A módosított programot el kell látni egy betöltővel, amely hivatott a programot beolvasni a megfelelő memóriahelyekre, valamint az alapvető hardware emulációt végrehajtani.

Módosítás hardware oldalról

Egy játékprogram esetében három dolgot kell megfelelően átalakítanunk: grafika, hang, irányítás.

Egyéb akadályok
Fejtörést okozhat több dolog is, pl. az IM2-es megszakítás szimulálása. Ez az a dolog, ami miatt több program nem fut az EMULÁTOR-on sem. Problémát okoz az 'EI' utasítás is (ENTERPRISE-on másképp kell végrehajtani), a 128K memórialapozás, a 128K zene (AY-3 8912 chip szimulálása), egyes ROM hívások, stb. Az ilyen speciális problémákra egy-egy aktuális rész kifejtése során fogunk kitérni.

Hasznos tanácsok

A program átírási manipulációhoz nem árt beszerezni egy disassembler-monitor programot, mivel e nélkül kicsit nehézkes lenne a dolgunk. Mi a SIMON (ASMON) nevű Z-80 fejlesztő-rendszert használtuk, ugyanis ez nem csak disassembler, hanem assembler is. Minden - később ismertetésre kerülő - példaprogram ezzel a rendszerrel lett előállítva.
Az sem árt, ha van a közelünkben egy SPECTRUM, persze ez nem létszükséglet, csak az eredetivel való egybevetéshez, ill. a BASIC betöltök listázásához kell. Célszerű egy software SPECTRUM EMULÁTOR beszerzése is, mivel a BASIC listázására ez is alkalmas.
Miért kell listázni a SPECTRUM verzió BASIC betöltőjét? Nos, a SPECTRUM programok általában egy BASIC betöltővel indulnak, a betöltő (LOADER) tölti be a program további részét (részeit). Ez egyrészt kényelmi szempontból jó (elég a LOAD"" utasítás, nem kell kiírni mögé a CODE függvényt), másrészt így egyszerien biztosítható az AUTOSTART). Ha nem listázzuk ki a BASIC betöltőt, akkor nem tudjuk a blokkok számát, az egyes blokkok betöltési címét, hosszát, s nem utolsó sorban a legfontosabbat, a program indítási címét. Természetesen a programok többsége nem engedi magát listázni, esetleg a betöltő maga is gépi kódú, vagy rejtett, ezekre a speciális esetekre is a megfelelő módszer ismertetésénél fogunk kitérni.

A kód átvitele

A SPECTRUM programok átírásának első lépcsőfoka magának a kódnak az átvitele egyik gépről a másikra. Ez esetünkben kézenfekvő, mivel a programok elnyomó többsége kazettán kerül az amatőrök kezébe. A feladat tehát az, hogy a SPECTRUM által felírt kazettákat elolvassuk. Szerencsére mindkét gépnek hasonló a kazettás magnót kezelő hardware felépítése.
Kicsit konkrétabban: a SPECTRUM 254-es (0FEH) porijának 5. bitje a kazettás adatrögzítés bemeneti bitje. A szalagról bejövő jel nagyságától függően vagy 1-be, vagy 0-ba állítja ezt a bitet.
ENTERPRISE-on a 182-es (0B6H) porton a 7. bit nagyjából hasonló feladatot lát el. Vagyis feladatunk eléggé leegyszerűsödik, mivel az eredeti loader-t kivehetjük a SPECTRUM ROM programjából, csak a hardware különbségeket kell korrigálni. Mi is ezt tettük a közölt programban. A példaprogram egy kicsit bonyolultabb, mert különböző luxusszolgáltatásai is vannak. Megértéséhez szükséges az EXOS (az ENTERPRISE operációs rendszere) ismerete.
Az EXOS használata a csatornák használatán alapul. Erre a SPECTRUM BASIC esetében is történtek próbálkozások, de korántsem sikerült annyira logikusan. A csatornák lényege az, hogy ha valamilyen egységet kezelni akarunk, akkor nem kezdünk el szeleburdi módon ROM-rutinokat hívni, hanem nyitunk számára egy kommunikációs csatornát. Azt, hogy milyen egységgel akarunk "szót váltani" a rendszer onnan tudja, hogy a csatorna megnyitásakor megadjuk az eszköz nevét. Ilyen eszközök a billentyűzet (KEYBOARD:), a nyomtató (PRINTER:) stb. Az EXOS onnan ismeri fel az eszközt, hogy kettőspont van a végén. Vannak olyan eszközök, amelyek file alapúak, és vannak olyanok is, amelyeknek csak a csatorna létrejötte szükséges. Például, ha kazettán létrehozunk egy file-t, akkor annak meg kell adnunk a nevét, adatokat kell beleírnunk, majd le kell zárni. A billentyűzet esetén nem akarunk file-t sem olvasni, sem írni, mi csak az éppen leütött billentyűre vagyunk kíváncsiak.
Egy csatorna, ha már létrejött, sok mindenre jó. Tudunk bele adatokat írni, adatokat olvasni. Csatornát EXOS funkcióhívással tehet megnyitni. Az EXOS funkcióhívás a következőképpen néz ki:

RST 30H
DEFB funkciókód

Általában az A regiszter tartalmazza a csaturna számot, DE-ben és BC-ben adunk át paramétereket. Visszatéréskor az "A" regiszter egy hibakódot tartalmaz, ami 0, ha sikeres volt a művelet. Mivel így elég nehézkes használni, ezért erre létrehoztak az ASMON-ban egy előre definiált makrót EXOS néven. Ennek használata: "EXOS funkciókód" ahol a funkciókód értelemszerűen a kívánt operációsrendszer szolgáltatás száma.

A programban használt EXOS hívások:

A
B=1
C=1
D=20
E=1

a csatornaszám
Az 1. funkció kijelölése
A videolapon az 1.sortól kezdve legyen megjelenítés
20 sort kell kijelezni
A képernyőn az 1. sorban kezdődjön a videolap

B=1
C=v
D=új érték.

A változót írni óhajtjuk
C regiszterben az EXOS változó száma
A hívás után ez lesz a változó új értéke.

Az operációs rendszer nagy vívmánya a szövegszerkesztő (EDITOR:). Nagysága abban áll, hogy ha valaki valamilyen szöveget akar a felhasználótól kicsikarni, nem kell új adatbekérő programot írnia. Ilyen esetekben elég, ha nyit egy csatornát "EDITOR:" néven, és máris javában olvashat a felhasználótól. Csatornamegnyitás előtt be kell állítani néhány paramétert (EXOS változót). Ezek:

Ennyi kitérő után lássuk, mit is tud a program:
Indítás után megkérdezi az átvitel módját, folyamatos, vagy nem folyamatos. Folyamatos mód esetén betölt egy SPECTRUM file-t, majd ezt kimenti, és ezt addig csinálja, amíg le nem lövik. A nem folyamatos mód abban tér el, hogy minden kimentés előtt vár egy billentyűleütésre, így ilyenkor lehet kazettát cserélni. A program bekér egy nevet, mögé tesz egy kiterjesztést formában, ahol y és xx szimbólikus jelölés. "y" helyére egy 1 karakteres jelet tesz, ami az első file esetén 0, ezután 1,2 stb. "xx" a beolvasott blokk típusát adja hexadecimálisan. Innen lehet felismerni, hogy ez most fejléc volt avagy programblokk.
A program az "ASMON" nevű assemblerrel készült, ha valaki csak "HISOFT GEN ASSEMBELER"-rel rendelkezik, ne csüggedjen, hanem az első sorok elé írja be a következőket:

EXOS MACRO@1
RST 30H
DEFB @1
ENDM

Az EXOS a sor elején kezdődjön, a többi sor egy (vagy több) karakterrel beljebb. Ez érvényes az egész programban is. A szimbólumokat bevezető SPACE nélkül írjuk be, míg a többi sorban lévő utasítások elé legalább egy SPACE-t tegyünk. Ez a programlistából is előtűnik. A szimbólumok és a mögötte álló utasítások közé szintén legalább egy SPACE szükséges. A bevitel módja ASMON-ra: a program bejelentkezése után nyomjuk meg az "E" billentyűt. Ekkor bekerülünk egy szövegszerkesztőbe. Itt írjuk be programunkat, majd nyomjuk meg az "F8" funkcióbillentyűt. Ekkor visszakerülünk a monitorba. Itt a "Z" billentyű lenyomásával beállíthatjuk az assembler opciókat. Addig nyomjuk az ENTER-t, amíg el nem jutunk az "Object file name:" kérdéshez. Ekkor írjuk be a program nevét (mindenkinek az ízlésére van bízva a névválasztás). Ezután újra ENTER, ekkor az "EXOS module header NO" üzenet látható. Nyomjunk meg egy fekete billentyűt (tehát nem a STOP-ot!!!), ekkor változik a kép, most már az "EXOS module header YES" szöveg olvasható. Adjunk ENTER-t. Most azt olvashatjuk, hogy "EXOS module type 0". Üssük be az "5" számot, majd újra az ENTER-t. Visszatértünk a "Command>" módba. Már csak egy teendőnk van, lefordítani a forrásszöveget. Ezt az "A" billentyű leütésével eszközölhetjük. Előtte ne felejtsük el felvételre állítani a magnót. Ha lemezegységünk van, akkor készüljünk fel arra, hogy a lemezen létrejön a programunk olyan néven, amit megadtunk neki. Ha az assembler valamilyen hibaüzenettel leáll, akkor nézzük meg, mit rontottunk el. A forrásszöveget is kimenthetjük a "W" paranccsal. Ekkor meg kell adnunk a file nevét, majd ENTER-t kell nyomni. A kimentett forrásszöveg a "K" paranccsal tölthető vissza. A GEN esetén be kell írni a forrásszöveget, majd "A,,R 5" és ENTER, ekkor lefordítja. Ha rendben ment a fordítás, akkor beírhatjuk: "O"név" és kimentődik a használható program.

Eme módfelett magasröptű program beírása után már akadálytalanul tudunk áthozni mindenféle programterméket. Ez így nagyon szép, de még ezzel sem tudunk működő SPECTRUM átiratokat gyártani, mert egyrészt még SPECTRUM képernyőnk sincsen, másrészt nem tudjuk betölteni sem. Ez a nemes feladatot megvalósító programocska lesz következő értekezésünk tárgya.

Forrásszöveg, Program

A képernyő

Miután már mindenki profi módon tud SPECTRUM programokat beolvasni, jogosan vetődik fel a tisztelt felhasználókban a kérdés, hogy az átmenekített adatokkal mit kezdjen. Egyszóval: hogyan tovább? A következő lépcsőfok az előző részben leírt módon emberközelibbé tett programok olyan környezetbe helyezése, ami minél inkább emlékeztet egy SPECTRUM-ra. A környezet legfontosabb eleme a képernyő. Enélkül a programok nagy része meglehetősen egysíkúvá válik. Első és egyben legmagasztosabb feladatunk elkövetni egy olyan képernyő formációt, ami kísértetiesen hasonlít a SPECTRUM-ra. Ez meglehetősen nehéz feladat, mivel a SINCLAIR gép eléggé Istentől elrugaszkodott módon végzi a kép kirakását. Vegyük sorra a jellegzetességeket:

Ennyi bevezető után térjünk rá programunk muködésére:
Először szerez egy kis memóriát, majd emulálja a SPECTRUM video üzemmódját. Ezt 192 db LPB segítségével teszi (az LPT felépítéséről már volt szó e hasábokon). Ezután betölt két file-t. Az ADDR1, BYTE1 ill. ADDR2, BYTE2 címkéket a betöltendő programtól függően kell értékkel feltölteni.
ADDR1 az első blokk, ADDR2 a második blokk betöltési címe. BYTE1 az első blokk, BYTE2 a második blokk hossza. A betöltött program indítási címe a USR szimbólumban kell hogy legyen tárolva.
Ha ezzel a betöltővel felfegyverkezve a vállalkozóbb szellemű Olvasó betölt egy játékprogramot, a betöltési képet meglátva valószínűleg elátkozza eme sorok íróját. Annak, hogy a tapasztalt szépséghibának mi az oka, hogyan lehet kiküszöbölni, a következő részben olvashatják a téma iránt érdeklődők!

Forrásszöveg

Az eddigiek során elfutottunk odáig, hogy fel tudunk építeni a SPECTRUM képernyőjéhez nagymértékben hasonlító SCREEN-t. Hogy ez miért csak hasonlító, és miért nem azonos, annak több oka van. Az előzőekben már volt szó az attribútum üzemmódról. Az attribútum memória az 5800H-5AFFH címtartományban helyezkedik el. Eme tartománynak a programátírások során igen nagy szerepe van, ezért érdemes jól megjegyezni. Vizsgáljunk meg egy attribútumbyte-ot! Kezdjük a legmagasabb helyiértékkel, a 7. bittel (b7)! Ha ez a bit be van állítva (értéke 1), akkor a papír és a tinta szín rövid időközönként invertálódik (magyarán: az adott karakter villog). Na ez az, amit az ENTERPRISE nem tud. Ha egyszer a sors szeszélye folytán olyan program kerül kezeink köze, amelyben létfontosságú a FLASH, akkor készüljünk fel a legrosszabbra. Nem lehetetlen ezt is szimulálni, de ez általában a programfutás sebességének rovására megy.) Tovább haladva, nézzük a 6. bitet (b6)! Ez a bit az un. BRIGHT (fényesség) bit. Ha ennek értéke 0, akkor a normál színek, míg a bit beállítása esetén a fényes színek jelennek meg. Az esetek túlnyomó többségében ez a bit okozza a galibát. A következő bitcsoport (b5,b4,b3) a papír színét (a nullás bitek a bittérképben), míg a legalsó 3 bit (b2,b1,b0) a tintaszínt (az egyes bitek a bittérképben) adja meg. Mivel ez 3 bit, így 8 szín kijelölésére van lehetőség. Ehhez jön még a BRIGHT bit, így kis jóindulattal azt mondhatjuk, hogy 16 szín között válogathat a felhasználó. A színképzést egyszerűen oldották meg: a három alapszínhez (vörös, zöld, kék) hozzárendeltek egy-egy bitet. A hozzárendelés: b0=kék: b1 =vörös, b2=zöld. (Ez így természetesen csak a tintaszínre igaz, papírszín esetén b0 helyett b3, b1 helyett b4 és b2 helyett b5 értendő.) Miután tisztáztuk a SPECTRUM színképzését, most a másik oldal következik. Az ENTERPRISE attribútum üzemmódja lényegesen egyszerűbb, nincsenek benne helyi specialitások (FLASH, BRIGHT). Az attribútumbyte két részre oszlik: alsó 4 bit és felső 4 bit. A felső 4 bit a papír, az alsó 4 bit a tinta színét jelöli ki (ahogy azt a logika diktálja). Látható tehát, hogy itt valóban 16 szín használatára van lehetőség. Ebből a 16 színből az alsó 8 (a 0xxx értékek) tetszőleges lehet. (A sorparaméter táblában, az LPB utolsó nyolc byte-ja éppen ezt a nyolc színt tartalmazza.) Előző mintaprogramunkban alkalmazott paletta jó közelítéssel megfelel a SPECTRUM normál színeinek. Amennyiben csak normál (nem fényes) színek fordulnak elő, akkor az egyedüli problémát az okozza, hogy a papír színek egy bittel alacsonyabban vannak, mint ahogy azt az ENTERPRISE megkívánná. Mielőtt bárki is fellelkesülne, sajnos le kell hűteni a kedélyeket. Már említettük a BRIGHT bitet. Nos, ha egy programban fényes színek is előfordulnak, akkor (mivel a b6 bit egyes állapotú) a fekete háttér helyett egy kellemes zöld alapszínt kapunk (no meg frászt, mivel semmit nem látunk a programból). Ilyen szempontból nagyon kellemes a fényes zöld tinta és a fekete papír kombinációja, ugyanis ennek értéke 44H. Ez azért jó, mert ez ENTERPRISE-on zöld papíron zöld tintát jelent, magyarán semmit. A megoldás bizonyára több olvasóban is felötlött: a fényes színeknek feleltessük meg a fennmaradó 8 színt (az 1xxx kombinációkat). Igen ám, de ez nem olyan egyszerű! Ezt a nyolc színt nem lehet csak úgy beállítani, használni kell a FIXBIAS regisztert. Ez a nevezetes regiszter a 128 (80h) port nagy részén terpeszkedik. Ez a port is bitenként értelmezett:

b7:
b6,b5:
b4-b0:

ha értéke 1, akkor a belső hangszóró néma.
a külső színbemenetek prioritását szabályozza.
FIXBIAS regiszter.

Mint látjuk ez a regiszter 5 bites. Tudni kell még azt is, hogy az ENTERPRISE a színeket 8 biten ábrázolja, így 256 színt képes használni. A felső nyolc szín (az 1xxx kombinációk) úgy képződik, hogy a FIXBIAS regiszter lesz a színbyte felső 5, míg a kiválasztott szín 3 bites érteke az alsó 3 bitje. A már említett programunk a FIXBIAS regiszterbe 0-t tölt. A NICK-chip bit-szín hozzárendelése azonban különbözik a SPECTRUM-étól: b0-vörös. b1-zöld, b2-kék. Vagyis ami SPECTRUM-on kék, az ENTERPRISE-on vörös. A megoldás egyszerű: a biteket úgy kell megcserélni, hogy a színek azonosak legyenek. Ez annyit jelent, hogy a programban el kell mélyedni, a színkezeléseket felderíteni, majd a kívánt értékre módosítani. Általában a programátírásban ez a mozzanat tart a legtovább, ez igényli a legnagyobb gyakorlatot. Tehát összefoglalva: ahhoz, hogy egy SCREEN hasonló színekben pompázzon, mint az eredeti, a következő módosítások kellenek:

  1. Ha az attribútumban a BRIGHT nincs beállítva, akkor a b3, b4, b5 biteket el kell mozdítani felfelé egy bittel, úgy, hogy az alsó 3 bit ne változzon.
  2. 2. Ha a BRIGHT bit be van állítva, akkor hasonló a procedúra, csak biteket is kell cserélgetni.
 
b7
b6
b5
b4
b3
b2
b1
b0
SPECTRUM attribútumbyte
0
1
s5
s4
s3
s2
s1
s0
ENTERPRISE attribútumbyte
1
s3
s5
s4
1
s0
s2
s1

E kis ábra után bizonyára mindenki tudna kreálni egy táblázatot, azonban, hogy az Olvasó idejét kíméljük íme az összes attribútumérték és a kiszámított ENTERPRISE megfelelő (forma: SPECTRUM-> Enterprise):

00=>00
01=>01
02=>02
03=>03
04=>04
05=>05
06=>06
07=>07
08=>10
09=>11
0A=>12
0B=>13
0C=>14
0D=>15
0E=>16
0F=>17
10=>20
11=>21
12=>22
13=>23
14=>24
15=>25
16=>26
17=>27
18=>30
19=>31
1A=>32
1B=>33
1C=>34
1D=>35
1E=>36
1F=>37
20=>40
21=>41
22=>42
23=>43
24=>44
25=>45
26=>46
27=>47
28=>50
29=>51
2A=>52
2B=>53
2C=>54
2D=>55
2E=>56
2F=>57
30=>60
31=>61
32=>62
33=>63
34=>64
35=>65
36=>66
37=>67
38=>70
39=>71
3A=>72
3B=>73
3C=>74
3D=>75
3E=>76
3F=>77
40=>88
41=>8C
42=>89
43=>8D
44=>8A
45=>8E
46=>8B
47=>8F
48=>C8
49=>CC
4A=>C9
4B=>CD
4C=>CA
4D=>CE
4E=>CB
4F=>CF
50=>98
51=>9C
52=>99
53=>9D
54=>9A
55=>9E
56=>9B
57=>9F
58=>D8
59=>DC
5A=>D9
5B=>DD
5C=>DA
5D=>DE
5E=>DB
5F=>DF
60=>A8
61=>AC
62=>A9
63=>AD
64=>AA
65=>AE
66=>AB
67=>AF
68=>E8
69=>EC
6A=>E9
6B=>ED
6C=>EA
6D=>EE
6E=>EB
6F=>EF
70=>B8
71=>BC
72=>B9
73=>BD
74=>BA
75=>BE
76=>BB
77=>BF
78=>F8
79=>FC
7A=>F9
7B=>FD
7C=>FA
7D=>FE
7E=>FB
7F=>FF
   

Ennek segítségével már lehetséges a színek átalakítása, azonban hosszabb adatmezőket már nem érdemes kézzel konvertálni. Mivel a számítógép az ember barátja, illő, hogy dolgozzon is egy kicsit. Az alábbi kis programmal SPECTRUM SCREEN-eket lehet konvertálni:

Forrásszöveg

A program használata: írjuk be az ASMON szerkesztőjébe. Amennyiben nem akarjuk minden egyes alkalommal újragépelni, akkor mentsük ki a <W> billentyű segítségével. Ekkor a "File name:" kérdésre adjunk egy nevet (ezt az Olvasó fantáziájára bízzuk). Célszerű egy külön kazettát (vagy lemezt) fenntartani a segédprogramoknak. Ha már kimentettek, legközelebbi alkalommal a begépelés helyett töltsük be ASMON-ba a "K" parancs segítségével. Az ismételten megjelenő "File name:" kérdésre adjuk meg az általunk kreált fantázianevet. Betöltődés után állítsuk be az assembler opciókat ("Z' parancs) az alábbiakra: 

Assembly listing OFF
List conditions NO
Force PASS 2 NO
Memory assembly YES
Memory offset 0
Object file name: 

Ez utóbbi esetben egyszerűen adjunk <ENTER>-t a kérdésre. Ezután fordítsuk le ("A" parancs) a programot, majd töltsünk be egy SPECTRUM SCREEN-t. Ez a SPECTRUM-on a 4000H címre töltődik be ás 1B00H hosszú (6912). A betöltés az <R> (Read BIN file) billentyű leütésével kezdhető el. Ekkor megjelenik a "Start:" kérdés. Erre a 4000 begépelésével válaszoljunk, majd <ENTER>. Ezután a "End:" kérdésre 5AFF-el válaszoljunk, majd ismét <ENTER>. Most már csak a "File name:"-re kell megadnunk a SCREEN nevét, és elindul a betöltés. A töltés végén megjelenik az "End of file" hibaüzenet, alatta pedig (ha jó csináltunk mindent) a "Last address:5AFF" szöveg. Ekkor futtassuk a programunkat: "G". majd a "Start:" kérdésre válaszoljuk a kezdőcímet, vagyis a 3000-et, ismét <ENTER>. Ha jól fordítottunk, akkor rövidesen a "Returned from CALL at 3000" választ kapjuk. Ekkor a memóriában már ott a konvertált SCREEN, csak ki kell menteni. Nyomjuk le az <S> gombot (Save BIN file). A "Start"-ra adjuk meg a 4000-et, "Stop"-ra 5AFF-et,"File name:"-re egy nevet. Az így kimentett SCREEN-t visszatölthetjük az előző részben ismertetett LOADER-rel. Végezetül annyit, hogy a program nem csak SCREEN-ek konvertalására jó, de minden más esetben módosítani kell a kezdőcímet és a hosszt. Természetesen csak SPECTRUM formátumról már ENTERPRISE file-formátumra hozott SCREEN-ek konvertálhatók a leírt módszerrel.

A betöltő rutin

Az eddigi számokban megpróbáltuk az alapokat tisztázni. Ezek megértése fontos a továbblépéshez. Az ASMON assembler-monitor program kezelését célszerű mihamarabb elsajátítani. Ezután a további fogásokat már egy konkrét példán keresztül fogjuk bemutatni. Az általunk választott program a "MOONCRESTA" nevet viseli, egy nemes mondanivalóval bíró űrhajós játékprogram. A választásnak több oka van:

  1. A program 1984-ben készült, a programozástechnikája ember közeli, ami az újabb, "hiperszonikus" programokról már nem mondható el.
  2. Terjedelme 20 kbyte alatt van, ami főleg a kazettás rendszerben dolgozók számára előnyösebb.
  3. Bizonyos mértékben hasonlít az állatorvosi lóra, mivel a programátírás fő buktatói benne vannak.
  4. Mivel régi program, így régi, rutinos SPECTRUM-osok való színűleg birtokolják.

Első lépésként próbáljuk kilistázni a BASIC részt (ha van rá lehetőségünk). Itt kezdődnek a problémák: a programot nem tudjuk leállítani. Ha valaki SPECTRUM-on próbálkozik, akkor szakirodalomban utána tud nézni az ilyen piszkos trükkök elleni védekezésnek. Mi ENTERPRISE-on, egy software SPECTRUM-emulátorral próbálkoztunk, ezeknek megvan az a jó tulajdonságuk, hogy le lehet BREAK-elni a programot közvetlenül betöltés után. Ha ez sikerült, még mindig nem érünk vele semmit, mert programlista helyett egy "O.K. boy" feliratot, és egy telefonszámot látunk. Megsúgjuk, hogy a sorszám nullára van állítva, ezért nem lehet vele mit kezdeni. Ezt a huncutságot egy POKE 23755,0:POKE 23756,1 parancssorral kivédhetjük. Ekkor az első sor száma 1 lesz. Ezt nyugodtan törölhetjük, mivel csak az üzenetet tartalmazza. Ha ezt megcsináltuk, akkor ismét nem tudunk mit kezdeni a programunkkal, mivel a védelem készítője a második sor sorszámát is kinullázta. Ezen a naivságon már csak gúnyosan mosolygunk, és megismételjük az előbbi POKE-okat. Most már van egy 1. sorszámú sorunk. Ezt a sort immáron önfeledten javíthatjuk. A sor elejéről a nem oda való grafikus karaktereket törölve előtűnik teljes pompájában a BASIC loader.

1 CLS: PRINT AT 10,10; FLASH 1;"loading"; FLASH 0;AT 12,9;"please wait ;TAB 7;"cracked by zec":
POKE PEEK 23633+256*PEEK 23634,PEEK 23647:POKE (PEEK 23633+256*PEEK 23634)+1,PEEK 23648 

Ebből megtudjuk azt a fontos információt, hogy egy "zec" nevű úriember törte fel az eredeti védelmet. Megnyugodhatunk tehát, a tolvajtól lopni nem bún. Ha ezt a sort is töröljük, akkor még mindig marad egy sor, amivel viszont már nem tudunk elbánni. Nem hát, mivel ez a gépi kódú loader, amit a BASIC igen rafináltan elindít. Disassemblálva a gépi kódú loader-t, a következű lista tárul ámuló szemünk elé:

LD SP,5BFFH
LD A,FFH
SCF
LD IX,B3B0H
LD DE,0100H
CALL  0556H
JP B3B0H

Egy ROM-listát előszedve tapasztalhatjuk, hogy ez nem csinál egyebet, mint beolvas egy fejléc nélküli programot a 0B3B0H címre, és ráugrik. Csavaros eszű Olvasóink bizonyára sejtik, hogy ez ismét egy loader lesz.

Elszántabb olvasóink okulva az előző részben leírtakból, már bizonyára betekintést nyertek a nevezetes 256 byte hosszú LOADER lelkivilágába. Aki még - kellő önbizalom hiányában - visszariadt ettől a lépéstől, annak megvilágítjuk e probléma hát terét. Mielőtt belemélyednénk, szeretnénk néhány tanácsot adni:

Ennyi kis kitérő után térjünk rá a lényegre:
Töltsük be az eredeti helyére a LOADER-t (ez az a kivétel ami a szabályt erősíti). Az eredeti hely esetünkben 0B3B0H, ez még a szabad memória területen belül van. A betöltött programot listázzuk ki ("L" parancs). Mivel tudjuk az indítási címét, érdemes itt próbálkozni (aki kőkemény egyéniség, természetesen próbálkozhat máshol is, de kijelentjük, hogy igazat szóltunk). Az indítási cím esetünkben adódik magától, mivel megegyezik a betöltési címmel. Ha elkezdjük listázni, akkor a következő látvány tárul ámuló szemeink elé:

B3B0
B3B3

B3B5

B3B6
83BA
B3BD
B3C0
83C2
B3C3
B3C7
B3CA
B3CD
B3CF
B3D0
B304
B307
B3DA
B3DD
B30E
B3E1

31 FF 5B
3E FF LD

37

DD 21 00 40
11 00 1B
CD E1 B3
3E FF
37
DD 21 C4 E8
11 3C 17 LD
CD El B3
3E FF
37
DD 21 76 77
11 A4 38
CD El B3
31 77 E6
F3
C3 E8 EA
14

LD SP,5BFF
A,FF

SCF

LD IX,4000
LD DE,1B00
CALL B3E1 
LD A,FF
SCF
LD IX,E8C4
DE,173C
CALL B3E1
LD A,FF
SCF
LD IX,7776
LD DE,38A4
CALL B3E1
LD SP,E677
DI
JP EAE8
INC D

;A verem beállítása
;Annak jelzése, hogy nem
; fejléc következik
;A töltés jelzése
(ha CY=0, akkor VERIFY)
;Blokk kezdőcíme
;Blokk hossza
;LOAD


;A lényeget lásd fent!







;A verem beállítása (ismét)
;Megszakítás tiltása
;Indítás
;Ez itt a LOAD szubrutin

Mielőtt valaki a szavahihetőségünket kétségbe vonná, sietünk leszögezni, hogy a megjegyzések, valamint a logikai egységelv szétválasztása a mi merényletünk. Látható, hogy a LOADER 6 logikai egységből áll. Az első egy normál vagy mezei LD SP,5BFF utasítás. Ennek a verem állításán kívül semmi szerepe sincs. A második egység már érdekesebb. Mivel látjuk, hogy 4000H-re töltődik, ráadásul 1B00H a hossza, besorolhatjuk a SCREEN skatulyába. A konvertálására az előző epizódban leírt játékszabályok érvényesek.
A harmadik és a negyedik egység végzi a munka oroszlánrészét: ők töltik be a tulajdonképpeni programot, ráadásul két részletben. Az egyik E8C4H-ra 173CH, a másik 7776H-ra 38A4H mennyiségű byte-ot tölt.
Az ötödik egység végzi a program végleges elindítását, érdemes megfigyelni, hogy EAE8H-n indul a MOONCRESTA.
Végül a hatodik egység, a LOAD szubrutin, amely a kazettáról betölti az egyes file-okat. Tévedés ne essék, ez nem egy sorból áll, sőt ez a leghosszabb szubrutin a LOADER-ben, viszont nem láttuk értelmét teljes egészében közölni. Akit érdekel, az tanulmányozhatja, nincs benne semmi extravagáns.

Ha valaki ennyi balszerencse ás sok-sok viszály után már a hetedik menyországban érezné magát, azt ki kelt ábrándítani. A cracker nagy showman lehetett, mivel még egy kis meglepetést tartogat a tarsolyában. Töltsük be a két modult! Az elsőt A8C4H-ra (ez már a 4000H-va alacsonyabb cím!), a másodikat 3776H-ra. Az első BFFFH-ic tart, a második 7018H-ig, erre a kimentésnél legyünk tekintettel! Listázzuk ki a programot az indítási címtől kezdve.

AAE8
AAEA
AAEC
AAEF
AAF2
AAF3

AAF6

AAF9
AAFC
AAFF
AB01

AB04

AB07
AB08
AB09
AB0A
AB0B
AB0C
AB0D
AB0E
AB11

AB12
A8C4

A8C7
A8CA
A8CB
ABCC
A8CD
A8CE
A8CF
A8D0
A8D1
A8D2
A8D5

3E 00
D3 FE
CD C4 E8
21 D6 E8
BE
CA 01 EB

21 48 EE

01 FF FF
11 49 EE
ED B0
21 11 EB

01 4A 00

7A
AE
77
23
0B
78
B1
C2 07 EB
03

55
21 00 40

01 00 1B
AF
AE
57
23
0B
78
B1
7A
C2 CB E8
C9

LD A,00
OUT (FE),A
CALL E8C4
LD HL,E8DE
CP (HL)
JP Z,EB01 

LD HL,EE48

LD BC,FFFF
LD DE,EE49
LDIR
LD HL,EB11

LD BC,004A
  
LD A,D
XOR (HL)
LD (HL),A
INC HL
DEC BC
LD A,B
OR C
JP NZ,EB07
INC BC

LD D,L    
LD HL,4000

LD BC,1B00
XOR A
XOR (HL)
LD D,A
INC HL
DEC BC
LD A,B
OR C
LD A,D
JP NZ,E8CB
RET

;A keret (BORDER) fekete
;Ellenorzo byte a SCREEN-ből
;Összehasonlítja az E8D6H
;memóriarekesz tartalmával
;Ha egyezik,
;EB01H-ra (AB01H) ugrik
;Ha nem egyezik
;(változtattunk a SCREEN-en)
;öngyilkos lesz


;Itt folytatja, ha helyes
;a SCREEN
;EB11H-n 4AH mennyiségű byte-ot
;XOR-ol
;az ellenőrző összeggel








;Látszólag értelmetlen rész,
;ezt a területet
;módosítja az előző rutin
;Az ellenőrző összeget
;képző szubrutin




;D-ben az ellenőrző összeg

Ezek után láthatjuk, milyen gonosz volt az illető. Nézzük végig a programot. Az E8C4H-n található rutin előállít egy számot. Ezt kiszámolhatjuk az eredeti SCREEN-ből, de felesleges, elég megnézni az E8D6H címen levő byte-ot. Az első néhány sort mindjárt megspórolhatjuk. EB01H-n van az első lényeges rész, a XOR-olás. Mivel tudjuk az ellenőrző kódot (ha valaki nem tudná, 22H), cselesen írhatunk egy kis szubrutint, ami elvégzi helyettünk eme nemes cselekedetet.
Mazochisták persze kézzel is megpróbálhatják. Mivel az elején található programrészre nem lesz szükségünk, ide beírhatjuk alkotásunkat. Ehhez szálljunk ki a listázásból (STOP vagy az ESC billentyű), majd nyomjuk meg az "M"-et. A módosítás címének kérésére adjuk az AAE8-at. Az ENTER lenyomása után kiíródik egy memóriadump, amiben tudunk módosítani. Szép sorban, az ENTER lenyomása nélkül írjuk be a következő számokat:

21 11 AB 06 4A 7E EE 22 77 23 10 F9 C9

Majd szálljunk ki a módosításból (STOP vagy ESC). Ha kilistázzuk ezt a kis programocskát, a következőket láthatjuk:

AAE8
AAEB
AAED
AAEE
AAF0
AAF1
AAF2
AAF4

21 11 AB
06 4A
7E
EE 22
77
23
10 F9
C9

LD HL,AB11
LD B,4A
LD A,(HL)
XOR 22
LD (HL),A
INC HL
DJNZ AAED
RET

Futtassuk le ("G" parancs, majd AAE8, ENTER), majd ha rendesen megkaptuk a "Retumed from CALL at AAE8" üzenetet, listázzuk ki az AB11 H címet. Micsoda változás!!

AB11
AB14
AB17
AB1A
AB1D
AB20
AB23
AB26
AB29
AB2C
AB2F
AB32
AB35
AB38
AB3B
AB3E
AB3F
AB41
AB44

21 77 77
01 A4 38
CD 47 EB
21 00 EE
01 00 12
C0 47 EB
21 77 77
01 A4 38
CD 51 EB
21 00 EE
01 00 12
CD 51 EB
21 10 A7
22 36 5C
01 5E 2F
AF      
ED 42   
31 2F 75
C3 6F 00

LD HL,7777
LD BC,38A4
CALL EB47
LD HL,EE00
LD BC,1200
CALL EB47
LD HL,7777
LD BC,38A4
CALL EB51
LD HL,EE00
LD BC,1200
CALL EB51
LD HL,A710 
LD (506),H1
LD BC,2F5E
XOR A
SBC HL,BC
LD SP,752F
JP 006F













;A karakterkészlet kezdőcíme
;a megfelelő változóba

Tanulságul álljon itt a program által használt két szubrutin is!

AB47
AB48
AB4A
AB48
AB4C
AB4D
AB4E
AB50

AB51
AB52
AB53
AB54
AB55
AB56
AB57
AB58
AB5A

7E
ED 67
23
0B
78   
B1
20 F7
C9

7A
AE
77
23
0 B
78
B1
20 F7
C9

LD A,(HL)
RRD
INC HL
DEC BC
LD A,B
OR C
JR NZ,AB47
RET

LD A,D
XOR (HL)
LD (HL),A
INC HL
DEC BC
LD A,B
OR C
JR NZ,AB51
RET

Látható, hogy a program többi része itt is el van rejtve. Ismét módosítani vagyunk kénytelenek. A módszer hasonló az előző programocska beviteléhez, de itt az AB0F címet kell módosítanunk az alábbi byte-okra:

16 22 21 77 37 01 A4 38
CD 47 AB 21 00 AE 01 00
12 CD 47 AB 21 77 37 01
A4 38 CD 51 AB 21 00 AE
01 00 12 CD 51 AB C9 

Ha ezt kilistázzuk, a következőket kell látnunk:

AB0F
AB11
AB14
AB17
AB1A
AB1D
AB20
AB23
AB26
AB29
AB2C
AB2F
AB32
AB35

16 22
21 77 37
01 A4 38
CD 47 AB
21 00 AE
01 00 12
CD 47 AB
21 77 37
01 A4 38
CD 51 AB
21 00 AE
01 00 12
CD 51 AB
C9

LD D,22
LD HL,3777
LD BC,38A4
CALL AB47
LD HL,AE00
LD BC,1200
CALL AB47
LD HL,3777
LD BC,38A4
CALL AB51
LD HL,AE00
LD BC,1200
CALL AB51
RET

Ha nem ezt látjuk, akkor vagy valami belerepült a szemünkbe, vagy elírtunk valamit (minden bizonnyal a Tisztelt Olvasó). Miután ezzel megvagyunk, futtassuk le ezt is ("G" AB0F, ENTER), és már meg is van a futtatható (átírható) programunk. Már csak egy akadály van hátra, nevezetesen az indítási cím. Aki azt hiszi, hogy ilyet már találtunk eleget, téved. Meg kell keresnünk a - sorrendben a harmadik - helyes belépési pontot. További tortúrák helyett ezt már a tudomására hozzuk azoknak a fanatikus programozóknak, akik idáig kitartottak (jutalom): 77B2H (illetve a 4000H eltolásos módszer esetében 37B2H). Hogy ez honnan származik? Ezt az Olvasóra bízzuk (csak annyit segítségül, hogy A710H-2F5EH az pontosan 77B2H, valamint a SPECTRUM ROM-ban a 6FH címen egy szál utasítás van, ez pediglen egy JP (HL) ).

Miután így sikerült lefegyvereznünk a védelmet, akár rá is térhetnénk a program tulajdonképpeni átírására. Sajnos azonban ez a kis ujjgyakorlás sok helyet elvett, így a lényeg legközelebbre marad. Addig is, senki ne feledje el kimenteni a verejtékes munkával feltört programrészeket. Míg mindenki szívszorongva várja következő próféciánkat, el lehet kezdeni az ismerkedést a programozók stílusával, meg lehet próbálkozni egy ENTERPRISE LOADER készítésével.

Végezetül érdemes összefoglalni az eddigi file-ok adatait:

SCREEN 4000H-ra kell tölteni, 1B00H hosszban.
CODE1 7776H-ra kell tölteni, 38A4H hosszban.
CODE2 E8C4H-ra kell tölteni, 173CH hosszban.

Ha mindent betöltöttünk, el kell ugrani a 77B2H címre.

Kellemes bogarászást!

Megszakítás

Ha valaki vette a fáradságot és előállította a program két blokkját, valamint átalakította a közölt betöltőt, csodálkozva tapasztalta, hogy a program nem igazán rendeltetésszerűen működik. Általánosságban elmondhatjuk, hogy ha egy program "elszáll", akkor annak két oka van:

  1. A SPECTRUM ROM-ban lévő szubrutint hív.
  2. Megszakítást alkalmaz.

Esetünkben mindkét esetre látunk majd példát, most foglalkozzunk a fontosabbal, a felhasználói megszakítással. A megszakítás olyan alprogram, amely a főprogram futása közben egy előre meghatározott esemény bekövetkeztekor hajtódik végre. Ez az esendő esemény esetünkben esetlegesen esik meg (jó mi?) mégpedig minden 1/50-ed másodpercben. A megszakítás elfogadásakor a processzor elmenti az aktuális programszámlálót (a PC regisztert), majd reagál, az üzemmódtól függően más ás más módon.
A Z80-as mikroprocesszornak 3 féle megszakításkezelése van:

  1. A nullás üzemmód. Ekkor a processzor a következő utasításbyte-ot nem az aktuális memóriacímről veszi, hanem a megszakítást generáló eszköz adja. A Z80 felhasználók ezt a módszert szinte nem is használják, az INTEL 8080 miroprocesszorral való kompatibilitás miatt építették be. Beállítása az "IM 0" Z80 utasítással történik.
  2. Az egyes üzemmód. Ekkor végrehajtódik egy "RST 38H" utasítás, vagyis meghívja a 38H-n lévő szubrutint. A SPECTRUM BASIC ezt használja. (Valamint az ENTERPRISE EXOS is!) Beállítása egy IM 1" (ED 56) utasítással történik.
  3. A kettes üzemmód. Ez a legcifrább, de a leghasznosabb is. A megszakítási alprogram címének megtalálásához meg kell néznünk egy speciális Z80 regisztert, az "Interrupt vector register" névre hallató "I" regisztert. Ebben az üzemmódban ugyanis megszakításkérés esetén a mikroprocesszor beolvas az adatvezetékekről egy byte-ot, a felső 8 bitnek megfelelteti az "I" regiszter 8 bitjét, majd az így létrehozott 16 bites címről kiolvas egy byte-ot, majd a 16 bites címet megnövelve még egyet. Az első byte lesz az alprogram címének alsó, a második pedig a felső byte-ja. Mire jó ez? Például arra, hogy ha több egység kérhet megszakítást, akkor nem a processzor kezdi el találgatni a megszakítani kívánó személyét, hanem a periféria azonosítja magát az adatbuszra küldött byte-al. A beállítása az "IM 2" (ED 5E) utasítással történik. Ezt az utasítást mindenki jól jegyezze meg, ugyanis a programok 80-90 százaléka ilyen üzemmódot állít be.

FONTOS! A megszakítást kiszolgáló alprogramnak nem szabad megváltoztatni EGYETLEN regiszter értéket sem, amelyet a főprogram használ! A megszakítás elfogadásakor tiltódik a további megszakítások elfogadása, ezt általában az interrupt alprogram végén szokták engedélyezni. Ez mind nagyon szép - mondhatja az Olvasó - de mi szükség van ennek ismeretére? Nagyon is van, mivel az ENTERPRISE bonyolultabb megszakítás elektronikával rendelkezik. Nem egy-, hanem mindjárt négyféle megszakítási forrás áll rendelkezésre, amelyek külön-külön tilthatok, engedélyezhetők. Erre egy külön perifériacím szolgál, melynek címe a 0B4H. Ez különbözik OUT és IN műveletek esetén. Minket csak az OUT érdekel, ezért csak ezt részletezzük.

A port bitenként értelmezett:

b0 A hanggenerátor által adott megszakítás engedélyezése. (1 érték által)
b1 A hanggenerátor megszakítás tároló törlése.
b2 Az 1 Hz-es megszakítás engedélyezése.
b3 Az 1 Hz-es megszakítás tároló törlése.
b4 A video-megszakítás engedélyezése.
b5 A video-megszakítás tároló törlése.
b6 A soros vonal megszakításának engedélyezése.
b7 A soros vonal megszakítás tárolójának törlése.

Az, hogy az engedélyezésnek mi a szerepe, elég egyértelmű, ha a megfelelő helyre egy egyes bitet írunk, akkor az a forrás képes megszakítást generálni. Ha nullát írunk, akkor letiltottuk az eszközt. Az 50 Hz-es megszakítás generálásához célszerű a NICKchip által generált megszakítást használni, amit az LPT generálásakor beállítottunk.

A másik feladat - a megszakítás tároló törlése - már nem ilyen egyértelmű. A DAVE-chip (amely a megszakításrendszert istápolja) tárolja az interrupt kéréseket. Amíg nem töröltük a tárolóját, addig elnyom minden ilyen irányú próbálkozást. Tehát: ha azt akarjuk, hogy az 1/50 másodpercenként érkező megszakítások ne vesszenek el (vagyis ne "fagyjon le" a program), minden megszakítást kiszolgáló alprogram végén (vagy elején) törölnünk kell a DAVE-chip megfelelő tárolóját. A video-megszakítás újraengedélyezését végző rutin az alábbi:

LD A,30H
OUT (OB4H),A

;b4 +b5, video IT. engedélyezés, tároló törlése
;A DAVE-chip megfelelo regisztere

Arra természetesen figyeljünk, hogy mentsük az "A" regiszter a művelet előtt.
Most nézzük meg, hogy a nagy fáradsággal átmentett "MOON CRESTA" hogyan csinálja. A program indítási címe 77B2H.

7782
77B3
77B6
7789
77BC
77BF
77C2
77C5
77C7
77CA
77CD
77D0
77D2
77D4
77D6
77D8
77DA

F3
31 43 F6
21 10 A7
22 36 5C
21 05 40
11 1B 5C
01 FB 1A
ED B0
21 00 F5
11 01 F5
01 01 01
36 77
ED B0
3E F5
ED 47
ED 5E
FB

DI
LD SP,F643
LD HL,A710
LD (5C36),HL
LD HL,4005
LD DE,5C7B
LD BC,lAFB
LDIR
LD HL,F500
LD DE,F501
LD BC,0101
LD (HL),77
LDIR
LD A,F5
LD I,A
IM 2
EI

;Megszakítás tiltása.
;Verem állítás.
;Karakterkészlet helyének
;tárolása az 5C36H címen.
;A betöltőkép tárolása



;Interrupt cím beállítása.


;A megszakítási rutin 7777H-n.

;A táblázat felső byte-ja (F5H)
;az "I" regiszterben.
;Kettes mód beállítás.
;Megszakítás engedélyezése.

Biztos mindenki megdöbbent a 257 elemű táblázaton. Erre azért van szükség, mivel a táblázat alsó byte-ja (amit a periféria ad) nem eléggé biztos. (Általában FFH) Ezzel a módszerrel minden kombinációra bebiztosították magukat a programozók. Az ilyen táblázatos módszerek leggonoszabbja az, amikor a táblazat csupa 255-ból áll, tehát a megszakítási rutin címe 65535 (FFFFH). Erre az egy byte-ra leraknak egy "JR" utasításnak megfelelő 18H-t, amelynek operandusa a 0 címen lévő (SPECTRUM BASIC) 0F3H. Ez a relatív ugrás visszaugrik a 0FFF4H címre, ahol egy ugró utasítás visz a tulajdonképpeni megszakítási alprogramra. A következő LOADER a kész játék végső betöltője, ezért érdemes beírni. A megszakítási problémát úgy küzdöttek le, hogy 7777H-ra (az IT rutin) letettünk egy "JP" utasítást, előbb engedélyezzük a DAVE-chipben az interruptot, majd ráugrunk a tulajdonképpeni rutinra.

Forrásszöveg

Mint látható, a program két blokkját nemes egyszerűséggel csak "ALSO" és "FELSO" névvel illettük, ezáltal is jelezve az elhelyezkedésüket. A betöltő elején található rutinok méltatására a későbbiekben visszatérünk. Ezzel a betöltővel futtatva a "MOON CRESTA"-t már hajlandó elindulni. (Igaz sok köszönet nincs benne!)

Billentyűzetfigyelés

És most essék néhány szó a SPECTRUM billentyűzetfigyeléséről: Az összes gomb egy mátrixba van kötve. A mátrix sorát mi közöljük a géppel igen ravasz módon, az oszlopot pedig szerény kérésünkre válaszként kapjuk. A sor kiválasztását igen érdekesen oldották meg. Kihasználták a mikroprocesszor ama tulajdonságát, hogy IN/OUT műveletek esetén a címbusz felső 8 bitjén is értékes adat van. Vegyünk példának egy IN A,(0FEH) utasítást!
Ekkor a címbusz alsó 8 bitje a periféria címét (jelen esetben a 0FEH-t), míg a felső 8 bit az "A" regiszter beolvasás előtti értékét tartalmazza. A másik fajta "IN" utasításcsoport esetén (az IN r,(C) ) a "B" regiszter kerül hasonló helyzetbe.
A SPECTRUM a billentyűket egy 8*5 elemű mátrixban kezeli. A 8 sor eléggé sokatmondó, mivel pontosan ennyi bit van egy byteban. A 8 sornak tehát megfelel 8 bit, amelyik bit 0 értékű, azt a sort olvassa be a processzor. Mivel egy byte-on belül bármelyik bit lehet 0, ezért egy utasítással több sort is le lehet kérdezni. A kiválasztott sort a 254-es (0FEH) porton lehet beolvasni, az alsó 5 bit hordozza a billentyűzet információit. Konkrétan: az 1,2,3,4,5 gombok vizsgálata az alábbi kis programocskával történhet.

1.variáció  2.variáció
LD A,0F7H
IN A,(0FEH)
LD BC,0F7FEH
IN A,(C)

Működés szempontjából a két módozat egyenértékű, a 2. variáció azonban használja a "BC" regiszterpárt. A gyakorlatban mindkét variáció előfordul.
Ha billentyűfigyelést keresünk egy programban, akkor a következő utasításokra figyeljünk fokozottan:

Utasítás 
HEXA kód

IN A,(0FEH)
IN A,(C)
IN B,(C)
IN C,(C)
IN D,(C)
IN E,(C)
IN H,(C)
IN L,(C)

DB FE
E0 78
ED 40
ED 48
ED 50
ED 58
ED 60
ED 68

Mielőtt bárki azt hinné, hogy az első két utasításon kívül mást nem használnak, az nem jár messze az igazságtól, viszont elrettentésül megjegyeznénk, hogy leltünk mar IN C,(C) utasítást is, amely az irányítás nemes feladatát volt hivatva betölteni. Gyakran előfordul a teljes klaviatúra lekérdezése is. Ez SPECTRUM-on egyszerű, ENTERPRISE-on viszont már nem. (Ha valaki nem tudná, egy

XOR A
IN A,(0FEH)

nagyon megfelelő ilyen célokra.)
A téma lezárásaként itt van a sokat emlegetett mátrix.

BIN
DEC
DEC
1
b0
2
b1
4
b2
8
b3
16
b4

11111110
11111101
11111011
11110111
11101111
11011111
10111111
01111111

254
253
251
247
239
223
191
127

FE
FD
FB
F7
EF
DF
BF
7F

Caps
A
Q
1
0
P
Enter
Space

Z
S
W
2
9
0
L
Symbol

X
D
E
3
8
I
K
M

C
F
R
4
7
U
J
N

V
G
T
5
6
Y
H
B

Miután a SPECTRUM klaviatúra-kérdést ilyen jól helybenhagytuk, rátérhetünk az ENTERPRISE oldalára. A mátrix módszer itt is alkalmazott, viszont - a több gomb miatt - némileg eltér a fent említettől. Először is, nem 8 sor van, hanem 10. Ez előrevetíti ama szomorú tény árnyékát, hogy nem fér egy byte-ban (vagyis csak a külön bites módszerrel nem). Másodszor: nem 5 oszlopot olvasunk be, hanem 8-at. Ezzel a módszerrel 80 gomb figyelésére van mód, ebből néhány nem használt. Azt, hogy melyik sort (0-tól 9-ig számozva) akarjuk olvasni, a 0B5H című porton kell közölnünk. Miután ezt közöltük, rendelkezésünkre áll ugyanezen a porton az adat. Előző példánknál maradva az 1-5 billentyűket az

LD A,3
OUT (0B5H),A
IN A,(0B5H)

utasításokkal figyelhetjük. Látható, hogy az előbbi 4 byte-tal szemben most ugyanez 6 byte hosszan sikerült. Vagyis nem fér be az eredeti helyére. Itt három dolgot tehetünk:

  1. Hagyjuk az egészet és elmegyünk dominózni.
  2. A memória egy nem használt helyére megírjuk szubrutinként, majd az eredeti programrészt lecseréljük egy "CALL" utasításra.
  3. Addig erőltetjük (jó VOGON szokás szerint) amíg nem sikerül begyurni az eredeti helyére.

Kétségkívül az első módszer a legegyszerűbb, viszont a harmadik a legszimpatikusabb, ennek ellenére mi a másodikat fogjuk bemutatni. Ennek okai: minek riasszuk el az Olvasót ilyen korai stádiumban? Végezetül íme, az ENTERPRISE billentyűzetmátrix:

Sor
b7
128
80H
b6
64
40H
b5
32
40H
b4
16
10H
b3
8
08H
b2
4
04H
b1
2
02H
b0
1
01H
0
1
2
3
4
5
6
7
8
9
B.SH.
CTRL
TAB
ESC
F1


ALT
INS
Z
A
W
2
F2
ERASE
]
ENTER
SPACE
X
S
E
3
F7
^
:
BAL
J.SH.
]
V
F
T
5
F5
0
L
HOLD
.
P
C
D
R
4
F6
-
;
FEL
/
@
B
G
Y
6
F3
9
K
JOBB
,
O
\
LOCK
Q
1
F8


LE
DEL
N
H
U
7
F4
8
J
STOP
M
I

Miután sikerült leimádkoznunk a védelmet a programról, valamint tisztáztunk néhány alapfogalmat, rátérhetünk munkánk érdemi részére.

Az előző részben már elindítottuk a "MOON CRESTA"-t, de egy kis DEMO-n kívül mást nem hajlandó csinálni. Az ok kézenfekvő: azért nem reagál a billentyűkre, mivel még a SPECTRUM módszerével figyeli azokat! Tehát a feladat:

  1. Felkutatni a vitás részeket és
  2. módosítani ENTERPRISE formára.

Töltsük be a két a programfile-t, majd használjuk az ASMON keresés funkcióját. (A funkció aktivizálására szolgáló billentyűt legcélszerűbb a "H" (HELP) billentyű lenyomása után megjelenő menüből kinézni. Angol gépeken a hatványjel.)
Először próbálkozzunk a legkézenfekvőbbel, az IN A,(0FEH) utasítással. A keresés billentyűjének lenyomása után megjelenik egy "Start:" kérdés, majd utána egy szám. Első kereséskor ide írjuk be a kezdőcímet, további keresésekhez elegendő "ENTER"-t nyomni, ekkor folytatja a keresést. Miután kijelöltük a kezdőcímet, a "Search:" kérdésre írjuk be az IN utasítás Z80 kódját. Aki olvasta az előző részt, már fejből tudja, aki nem olvasta, az szégyellje magát! De már-már közmondásos nagylelkűségünknek engedve eláruljuk, hogy 0DBH. Tehát a "Search:" kérdésre gépeljük be azt, hogy "DB FE". Az idézőjel természetesen nem kell, mivel ha kitesszük az idézőjeleket, akkor azt a karaktersorozatot fogja keresni. Miután leütöttük az "ENTER"-t, kis gondolkozás után a "Found at:" üzenet ás egy memóriacím, alatta pedig három sorban memóriadump jelenik meg. Ha nem ez történne, akkor áldásos tevékenységünk mégsem volt annyira áldásos.
Most vegyük a kedvezőbb esetet, tételezzük fel, hogy sikeres volt az akciónk. Közbevetőleg egy jótanács! Keresésnél a kiírt címnél mindig néhány byte-tal alacsonyabb címtől kezdjük a listázást!
Nos, nézzük, mit találtunk.

3887
3889
388A
388C
388E
3890
3893
3894

06 00
AF
DB FE
E6 1F
FE 1F
C2 E3 79
76
10 F3

LD B,00
XOR A
IN A,(FE)
AND 1F
CP 1F
JP NZ,79E3
HALT
DJNZ 3889

(A memóriacímek természetesen 4000H-val magasabban értendők!)
Mit is csinál ez a kis rutin? A lényeg a

XOR A
IN A,(FE)

rész. A "XOR A" utasítás saját magával végez "kizáró VAGY" kapcsolatot. Ezt bitenként végzi, vagyis a 0.bitet a 0.bittel stb... A "XOR" művelet akkor ad "1" értéket, ha a két bit különböző. Mivel az "A" regiszter teljesen illogikus módon megegyezik saját magával, ezért a "XOR A" művelet eredménye mindig 0-t ad. Egyébként ez a módszer nagyon elterjedt a "LD A,0" (2 byte) utasítás helyett (mivel ez csak egy byte). Az "IN A,(FE)" utasításról volt már szó. Ha az "A" regiszterben nulla van, az az összes sort kijelöli, vagyis a teljes billentyűzetet leolvassa.
A következő, "AND 1F" utasítás csak a billentyűzetről származó adatokat tartja meg. Ezután megnézi, hogy volt-e lenyomott billentyű (CP 1F). Ha volt, akkor az "A" nem 1FH lesz, ekkor elugrik a 79E3H címre, ha nem volt lenyomott billentyű, akkor vár 1/50 másodpercet, majd újra leolvassa a klaviatúrát, és ez így megy 256-szor. (A "DJNZ" utasítást illik ismerni!)
Miután így a felderítést letudtuk, a következő feladat a probléma leküzdése. Ez már kicsit bonyolultabb, de nem kell kétségbe esni! Az valószínűleg világos, hogy ide nem fér be az általunk elkészíteni szándékozott helyettesítő szubrutin. Az előző számban közöltünk egy LOADER-t a programhoz. Annak az elején volt néhány szubrutin, amit nem részleteztünk kellőképpen (mondhatni sehogyan). Örömmel közöljük, hogy ez a felemelő pillanat most érkezett el! (Legalábbis részben.)
A betöltő így kezdődik:

ORG 256
JP CONT
JP KEY
JP ALLKEY
JP JOY
JP BEEP


;100H
;103H
;106H
;109H
;10CH

A megjegyzés rovatban az egyes JP utasítások címei lettek feltüntetve hexadecimálisan. Az ilyen JP utasításokból álló programrészt hívják ugrótáblázatnak. Kicsit nagyképűen mi is ilyen névvel fogjuk illetni. Mint látható, mindegyik egy-egy rutinra ugrik. Teljesen jogos a kérdés, hogy mi szükség van erre, amikor a rutinokat direkten is lehetne hívni? Ez teljesen igaz, viszont, ha egy rutint megváltoztatunk (például beszúrunk egy byte-ot), az összes többi is megváltozik. Ekkor az összes hivatkozást meg kellene változtatni, ami esetünkben pI., az "ALLKEY" nevű szubrutin esetén eléggé munkaigényes (és felesleges). Az ugrótáblázat alkalmazásával ez a probléma elveszti jelentőségét, mivel itt csak az egyes JP-okat kell módosítani.
Természetesen, ha valaki úgy írja meg a kellő részeket, hogy azokat később nem kell módosítani, akkor nincs szükség az itt leírtakra. Azonban - minden ellenkező híreszteléssel ellentétben - senki sem tökéletes, mindenki követhet el hibákat (sőt, csak azt!), így szerény véleményünk szerint az általunk eloadott módszer a legkevésbé fáradságos!
Az imént már emlegettük az "ALLKEY" szubrutint, a szemfülesebbek biztosan kitalálták, hogy nem véletlenül! Mint neve is sejtetni engedi, ez a teljes billentyűzetet lekérdező rutin. vizsgáljuk meg a működését!

ALLKEY




A1

PUSH BC
LD BC,0AFFH



LD A,B
DEC A


OUT (0B5H),A

IN A,(0B5H)

AND C
LD C,A


DJNZ A1


POP BC

RET 

;A BC regiszterpár elmentése
;B=0AH, C=0FFH
;B: 10 sor van a billentyűzeten
;C: minden oszlop inaktív
;(kezdetben)
;A=sor
;A=A-1, mivel nem 10-től l-ig,
;hanem 9-tol 0-ig van a
;billentyűzet sorszámozása
;A sorszám kiküldése a megfelelő
;portra
;Az oszlop érték visszaolvasása
;0FFH, ha nincs lenyomva gomb

;Ha valamelyik sorban volt lenyomva
;billentyű, akkor a "C" regiszter
;nem lehet 0FFH
;Mind a 10 sor leolvasása
;Az "A" regiszterben is
;megtalálható a végérték
;A "BC" regiszterpár
;visszatöltése
;Visszatérés

Ezzel a kis programmal szimuláljuk a teljes billentyűzetleolvasást, egy "CALL 106H' utasítással hívhatjuk. Látható, hogy ez is három byte a

XOR A
IN A,(FE)

-hez hasonlóan, tehát gond nélkül elhelyezhető elődje helyén.
A "CALL 106H" utasítás gépi kódja: CD 06 01 (hexában), tehát az előző programrészt módosítsuk a következőre:

3887
3889
388C
388E
3890
3893
3894

06 00
CD 06 01
E6 FF
FE FF
C2 E3 79
76
10 F3

LD B,00
CALL 0106
AND FF
CP FF
JP NZ,79E3
HALT
DJNZ 3889

Talán feltűnt, hogy az "AND 1F" utasítást "AND FF"-re és a "CP 1F"-et "CP FF"-re cseréltük, ez a teljes billentyűzet figyelése miatt szükséges.
Miután ily módon átestünk a tűzkeresztségen, folytathatjuk a keresést.

3967
3969
396A
396C
396E
3970
3973
3974
3994
3996
3997
3999
399B
399D
39A0
39A1
39BF
39C1
39C2
39C4
39C6
39C8
39CB
39CC
39D4
39D6
39D7
39D8
39DA
39DC
39DE
39E1

06 14
AF
DB FE
E6 1F
FE 1F
C2 E3 79
76
10 F3
06 1E
AF
DB FE
E6 1F
FE 1F
C2 E3 79
76
10 F3
06 64
AF
DB FE
E6 1F
FE 1F
C2 E3 79
76
10 F3 
06 00 
76
AF
DB FE
E6 1F
FE 1F
C2 E3 79
10 F3

LD B,14
XOR A
IN A,(FE)
AND 1F
CP 1F
JP NZ,79E3
HALT
DJNZ 3969
LD B,1E
XOR A
IN A,(FE)
AND 1F
CP 1F
JP NZ,79E3
HALT
DJNZ 3996
LD B,64
XOR A
IN A,(FE)
AND 1F
CP 1F
JP NZ,79E3
HALT
DJNZ 39C1
LD B,00
HALT
XOR A
IN A,(FE)
AND 1F
CP 1F
JP NZ,79E3
DJNZ 39D6

Ezek mind egy kaptafára készültek, kár is rájuk több szót vesztegetni, az eddigiek alapján csak rutinmunka az átírásuk.
A most következő viszont annál érdekesebb!

3C10
3C11
3C13
3C15
3C17

AF
DB FE
E6 1F
FE 1F
C2 10 7C

XOR A
IN A,(FE)
AND 1F
CP 1F
JP NZ,7C10

Ez, ugyebár ismerős?

3C1A
3C1C
3C1E
3C20
3C22

06 00
3E EF
DB FE
CB 67
CA 31 81

LD B,00
LD A,EF
IN A,(FE)
BIT 4,A
JP Z,8131

Akik rendelkeznek az előző számban szereplő, nagy kaliberű SPECTRUM billentyű-táblázattal, már tudhatják, hogy ez a "6" billentyűt figyeli.

3C25
3C27

3E F7
DB FE

LD A,F7
IN A,(FE)

Az "A" regiszterben az "12345" billentyűknek megfelelő sor.

3C29
3C2B
3C2E
3C30
3C33

CB 47
C2 36 7C
3E 01
32 C2 87
C3 5E 7B

BIT 0,A
JP NZ,7C36
LD A,01
LD (87C2),A
JP 7B5E

Az "1" billentyű esetén a 87C2H memóriacímre betölt 01H-t, majd ráugrik a 7B5EH címre.

3C36
3C38
3C3B
3C3D
3C40

CB 4F   
C2 43 7C
3E 02   
32 C2 87
C3 5E 7B

BIT 1,A
JP NZ,7C43
LD A,02
LD (87C2),A
JP 7B5E

A "2" billentyű hasonlóképpen.

3C43
3C45
3C48
3C4B

CB 57
C2 4E 7C
32 5E F3
C3 5E 7B

BIT 2,A
JP NZ,7C4E
LD (F35E),A
JP 7B5E

A "3" billentyű.

3C4E
3C50
3C53
3C54
3C57

CB 5F
C2 5A 7C
AF
32 5E F3
C3 5E 7B

BIT 3,A
JP NZ,7C5A
XOR A
LD (F35E),A
JP 7B5E

A "4" billentyű.

3C5A
3C5C

CB 67
CA DB 7C

BIT 4,A
JP Z,7CDB

"5" esetén folytatja a 7CDBH címen, egyébként várakozik, majd újraolvassa a billentyűzetet 256-szor.

3C5F
3C60
3C62

76
10 BA
C3 52 78

HALT
DJNZ 3C1C
JP 7852

7852H-n folytatja, ha több mint 5 másodpercig nem nyomjuk meg az 1-6 billentyűk közül valamelyiket.
Talán kitalálták már, hogy ez itt a menü volt. Most mit tegyünk?
Az látható, hogy itt sem fér be a módosított rutin az eredeti helyére, viszont van a mi kis betöltőnkben egy "KEY" nevű szubrutin (103H a belépési pontja). Eléggé furcsán néz ki:

KEY

EX (SP),HL



LD A,(HL)

INC HL
EX (SP),HL
OUT (0B5H),A
IN A,(0B5H)
RET

;HL és a STACK-ban lévő 16 bites
;adat kicserélése
;Ekkor (ha CALL-al hívjuk meg) a
;visszatérési cím található itt
;A visszatérési címen található
;byte betöltése "A"-ba
;A visszatérési cím növelése eggyel.
;HL visszatöltése

A szubrutin hívása némi hasonlóságot mutat az EXOS hívásával:

CALL 103H
DEFB SOR

Például, ha a számok sorát akarjuk beolvasni, adjuk ki a

CALL 103H
DEFB 3

utasításokat.
Előző programrészletünk módosítva:

3C10
3C13
3C15
3C17
3C1A
3C1C
3C1F
3C20
3C22
3C25
3C28
3C29
3C2B
3C2E
3C30
3C33
3C36
3C38
3C3B
3C3D
3C40
3C43
3C45
3C48
3C4B
3C4E
3C50
3C53
3C54
3C57
3C5A
3C5C
3C5F
3C60
3C62

CD 06 01
E6 FF
FE FF
C2 10 7C
06 00
CD 03 01
03
CB 57
CA 31 81
CD 03 01
03
CB 4F
C2 36 7C
3E 01
32 C2 87
C3 5E 7B
CB 77
C2 43 7C
3E 02
32 C2 87
C3 SE 7B
CB 6F
C2 4E 7C
32 5E F3
C3 5E 7B
CB 5F
C2 5A 7C
AF
32 5E F3
C3 5E 7B
CB 67
CA DB 7C
76
10 BA
C3 52 78

CALL 0106
AND FF
CP FF
JP NZ,7C10
LD B,00
CALL 0103
INC BC
BIT 2,A
JP Z,8131
CALL 0103
INC BC
BIT 1,A
JP NZ,7C36
LD A,01
LD (87C2),A
JP 7B5E
BIT 6,A
JP NZ,7C43
LD A,02
LD (87C2),A
JP 7B5E
BIT 5,A
JP NZ,7C4E
LD (F35E),A
JP 7B5E
BIT 3,A
JP NZ,7C5A
XOR A
LD (F35E),A
JP 7B5E
BIT 4,A
JP Z,7CDB
HALT
DJNZ 3C1C
JP 7852







; ADAT
; megváltozik a bitkiosztás


; ADAT
; Az "1" bilentyű




; A "2" billentyű




; A "3" billentyű



; A "4" billentyű




; Az "5" billentyű

Ha ezzel is megvagyunk, folytathatjuk önfeledt módosítgatásainkat:

3D15
3D17
3D18
3D19
3D1B
3D1D
3D1F
3D22
3D24
3DA2
3DA4
3DA5
3DA6
3DA8
3DAA
3DAC
3DAF
3DB1
3E2F
3E31
3E32
3E33
3E35
3E37
3E39
3E3C
3E3E
3EBB
3EBD
3EBE
3EBF
3EC1
3EC3
3EC5
3EC8
3ECA
3F4C
3F4E
3F4F
3F50
3F52
3F54
3F56
3F59
3F5B

06 19
76
AF
DB FE
E6 1F
FE 1F
C2 27 7D
10 F3
C3 FE 7C
06 19
76
AF
DB FE
E6 1F
FE 1F
C2 B4 7D
10 F3
C3 8A 7D
06 19 LD
76
AF
DB FE
E6 1F
FE 1F
C2 41 7E
10 F3
C3 18 7E
06 19 LD
76
AF
DB FE
E6 1F
FE 1F
C2 CD 7E
10 F3
C3 A4 7E
06 19
76
AF
DB FE
E6 1F
FE 1F
C2 5E 7F
10 F3
C3 34 7F

LD B,19
HALT
XOR A
IN A,(FE)
AND 1F
CP 1F
JP NZ,7D27
DJNZ 3D17
JP 7CFE
LD B,19
HALT
XOR A
IN A,(FE)
AND 1F
CP 1F
JP NZ,7DB4
DJNZ 3DA4
JP 7D8A
B,19
HALT
XOR A
IN A,(FE)
AND 1F
CP 1F
JP NZ,7E41
DJNZ 3E31
JP 7E18
B,19
HALT
XOR A
IN A,(FE)
AND 1F
CP 1F
JP NZ,7ECD
DJNZ 3EBD
JP 7EA4
LD B,19
HALT
XOR A
IN A,(FE)
AND 1F
CP 1F
JP NZ,7F5E
DJNZ 3F4E
JP 7F34

És most ismét kizökkent bennünket valami kedvenc szórakozásunkból!

3FD9
3FDB
3FDC
3FDE
3FE0
3FE2
3FE5
3FE7
3FE9
3FEB
3FEE
3FF0

06 19
76
3E DF
DB FE
CB 67
CA F3 7F
3E 7F
DB FE
CB 5F
CA DB 7C
10 EB
C3 C3 7F

LD B,19
HALT
LD A,DF
IN A,(FE)
BIT 4,A
JP Z,7FF3
LD A,7F
IN A,(FE)
BIT 3,A
JP Z,7CDB
DJNZ 3FDB
JP 7FC3






; Az "Y" billentyű



; Az "N" billentyű

Ezt már akár bekötött szemmel is meg lehet csinálni!

3FD9
3FDB
3FDC
3FDF
3FEO
3FE2
3FE5
3FE8
3FE9
3FEB
3FEE
3FF0

06 19
76
CD 03 01
02
CB 57
CA F3 7F
CD 03 01
00
CB 47
CA DB 7C
10 EB
C3 C3 7F

LD B,19
HALT
CALL 0103
LD (BC),A
BIT 2,A
JP Z,7FF3
CALL 0103
NOP
BIT 0,A
JP Z,7CDB
DJNZ 3FDB
JP 7FC3




;ADAT
; Az "Y" billentyű


; ADAT
;A "N" billentyű

Ezután már csak egy fontos dolgunk van:

42A4
42A5
42A7
42A9
42AB

AF
DB FE
E6 1F
FE 1F
CA B3 82

XOR A
IN A,(FE)
AND 1F
CP 1F
JP Z,82B3

Még ezután is van billentyűzetfigyelés, de azt már legközelebbre hagyjuk.

Ha az imént leírt módosításokat elvégezzük (és ki is mentjük!), már be tudjuk állítani a vezérlés módját, a játékosok számát, valamint mindezek méltó megkoronázásaként el is tudjuk indítani a programot. Játszani ugyan nem tudunk vele - mivel igen gyorsan lefagy -, de megtettük az első fontos lépést. Azt, hogy miért fagy le, valamint az egyéb ROM-hívások előtalálásának módozatait legközelebb ecseteljük.

ROM hívások

Örömmel közölhetjük, hogy sorozatunk egy történelmi pillanathoz érkezett!

Az alábbiakban leírtak szerint eljárva végre működőképessé varázsolhatjuk mindenki szeretett MOON CRESTA-ját. Legutóbb odáig jutottunk, hogy elindul a játék, de rögvest meg is dermed. Már említettük - valamikor a múlt ködébe veszően - a "lefagyás" lehetséges okait. Mivel az első számú közellenséget (az interruptot) már kétvállra fektettük, marad a nem kevésbé alattomos ROM hívás. (Természetesen más ok előfordulhat, például elfelejtettük bekapcsolni a gépet.) Miután a követendő utat szellemünk lángoló fáklyaként már bevilágította, már csak elő kellene találni a hívások helyeit. Erre alkalmas az itt következő kis program:


L1





L2

ORG 1000H
LD A,(IX)
INC IX
CP 0CDH
JR Z,L2
CP 0C3H
JR NZ,L1
LD L,(IX+0)
LD H,(IX+1)
LD BC,4000H
OR A
SBC HL,BC
JR NC,L1
RET

;Ide fordítjuk


;CALL utasítás?
;Ha igen, akkor L2
;JP utasítás?
;Ha nem, akkor következő byte
;Operandusok vizsgálata

;Ha nem a ROM-ra vonatkoznak


;következő utasítás keresése
;Ha egy ROM hívás, visszatérés

A program megértéséhez annyit kell tudni. hogy SPECTRUM-on a ROM a 0000H-3FFFH címtartományban helyezkedik el. A "CALL" Z80 utasítás kódja HEXA 0CDH, a "JP" kódja pedig 0C3H. Fordítsuk le a programot a memóriába 0 oflsettel. IX regiszterbe írjuk be a program kezdőcímét ("X" parancs, majd a "Registerpair:" kérdesre írjuk be az "IX"-et, a "Value:" kérdésre pedig a program kezdőcímét.) Ezután "G", majd a "Start:" kérdésre adjunk 1000-et. Amennyiben a program talált valamit, egy hanghatás után visszatér az ASMON-ba. Ekkor IX a ROM hívás operandusára fog mutatni.

FIGYELEM!
Nem mind arany, ami fénylik! Véletlenszemen is előfordulhatnak olyan byte kombinációk, amik megegyeznek a ROM hívással. Ezért amint találtunk valamit, a reménybeli hívás címétől számoljunk vissza néhány byte-ot, majd innen listázzuk ki a programot. Ha a listázás során értelmes kódot latunk, valamint a ROM hívás is látható, akkor valószínűleg megtaláltuk. A programban szereplő ÖSSZES hívást javítsuk ki.

Leggyakrabban eloforduló hívások:

006FH
007CH
028EH
03R5H
04C2H
055CH
22B0H

Egy "JP (HL)" utasítás.
Egy "RET" utasítás.
KEY-SCAN rutin (billentyűzet leolvasó)
BEEP rutin (hangkiadó rutin)
SAVE rutin
LOAD rutin
PIXEL-ADD rutin (képpont címének kiszámítása)

Kanyarodjunk vissza kedvenc MOON CRESTA programunkhoz. Ha itt keressük a ROM hívásokat, elég sokat találunk. Köszönhető ez annak, hogy a billentyű figyeléseket már kijavítottuk saját rutin hívásokra, amik az alsó 16k területen vannak, imigyen kimerítve a SPECTRUM ROM fogalmát. Viszont a sok álhívás mögött meglapulva akad néhány igazi is. Ezek:

5398
5398
539C
539F
53A2
53A5

2A C4 87
23
22 C4 87
11 01 00
CD B6 03
FD 21 48 89

LD HL,(87C4)
INC HL
LD (87C4),HL
LD DE,0001
CALL 03B6
LD IY,8948

(A címekhez 4000H-t hozzá kell adni!)
A 03B6H ugyan kimaradt a felsorolásból, de ez mégis a BEEP rutin, csak a kezdeti "DI" utasítást ugorja át a program. A LOADER-ben a 010CH címen kezdődik egy rutin amely feladatáról nem szóltunk, ez a BEEP rutin ENTERPRISE környezetre honosítva. Tehát a javítás így néz ki:

53A2

CD 0C 01

CALL 0100

Még két ilyen ilyen hívás van, ezeket nem részletezzük:

561A
561D
5620
5623
5626

5620

6594
6595
6596
6599
659B
659C
659F
65A2

659C

11 01 00
21 58 02
CD B6 03
FO 6E 00
26 FF

CD 0C 01

7A
83
CA A7 A5
CB 7A
C0
CD B6 03
11 04 00
FD 19

CD 0C 01

LD DE,0001
LD HL,0258
CALL 0386
LD L,(IY)
LD H,FF

CALL 010C

LD A,D
OR E
JP Z,A5A7
BIT 1,0
RET NZ
CALL J3B6
LD DE,0004
ADD IY,DE

CALL 010C

Ha a javításokat kimentjük, majd betöltjük a programot, már elindul, zenél és játszana, ha tudnánk irányítani. (A zene idézőjelben értendő, nem sokkal múlja felül pl. a BROS színvonalát)

Botkormány

Előfordulhat olyan Olvasó is, aki maga is szeretne aktív részese lenni a játéknak (elégedetlenek mindig vannak). Az ilyen extrém kívánságok teljesítését szolgálja a betöltőben lévő "JOY" nevezetű szubrutin. Működésérői csak annyit, hogy ENTERPRISE-on a két külső joystick leolvasása a 0B6H porton lehetséges. A módszer teljesen hasonló, mint a billentyűzet esetében. A kívánt iránynak megfelelő értéket a 0B5H portra kell kiküldeni, majd a választ a 0B6H port 0.bitjén olvashatjuk be. Ha aktív az irány, akkor a bit 0 értékű. Az irányoknak megfelelő értékek (a külső 1. joystick az EXT1, a külső 2. pedig az EXT2 nevet viseli).

0 - EXT1 tűz
1 - EXT1 fel
2 - EXT1 le
3 - EXT1 balra
4 - EXT1 jobbra
5 - EXT2 tűz
6 - EXT2 fel
7 - EXT2 le
8 - EXT2 balra
9 - EXT2 jobbra

A JOY rutin leolvassa mindkét joystick állapotát, majd ezt az értéket visszaadja az "A" regiszterben, a következő bitkiosztásban:

b0 - jobbra
b1 - balra
b2 - le
b3 - fel
b4 - tűz

A rutin az "RST 28H" utasítással hívható, az aktív irányt a bit 1 állapota jelzi. Az egyszerűség kedvéért a játékban csak a joystick vezérlést írtuk át. A program SPECTRUM-on a KEMPSTON-rendszerű illesztővel üzemel (a JOYSTICK CONTROL územmódban). KEMPSTON joystick esetében a botkormány állapotát a decimális 31 (HEXA 1 FH) portról lehet beolvasni. A bitkiosztás megegyezik rutinunk bitkiosztásával, itt is az 1 állapot az aktív. Tehát nincs más teendőnk, mint előkeresni az összes "IN A,(1FH)" utasítást (2 byte) és kicserélni egy "RST 28H" utasításra (1 byte, a másik byte-ot 0-ra írjuk át).

A joystick figyelés előfordulási helyei:

502BH
5032H
5039H
B023H
B053H
6246H
6259H
626EH
Ezek az "ALSO" file-ban vannak

Ezek a "FELSO" file-ban vannak.


Például:
5028 DB 1E
Ezt kell
5028 EF 00
javítani.
IN A,(1F)

RST 28-ra

Ha így felszereljük programunkat, betöltjük, majd a '4' billentyűvel JOYSTICK CONTROL opcióba állítjuk, végezetül pedig a '6' billentyűvel elindítjuk a játékot, már lőhetjük is önfeledten a gonosz ellenséges űrhajókat. Azaz...
A színek nem mondhatók éppen ideálisnak - sőt - és a harmadik pályán zöld alapon zöld szín adódik, amitől a zöld csillagokat is vörösnek látjuk. Ezen probléma (amely egyben az utolsó) leküzdéséhez legközelebb adunk tanácsokat...

Színkonverzió

Örömmel tudatjuk Olvasóinkkal, hogy elérkeztünk az utolsó, és egyben legnehezebb feladatunkhoz, Talán még emlékeznek, hogy kedvenc MOON CRESTA nevű programunk már elindul, játszani lehet vele, de a színek összeállítása meglehetősen avantgard. Az alábbiakban eme kellemetlenség megszüntetéséhez szeretnénk néhány ötletet közölni.
A színek megváltozásának okáról a betöltőkép javítása során már volt szó, így ezt nem részletezzük. A program által generált színek esetében csak annyival bonyolultabb a helyzet, hogy ilyenkor nem tudni, a program melyik részében foglalkozik az attributum memóriával. A sikeres színjavítás feltétele, hogy képesek legyünk a vitális részeket megkeresni a programban.

Hogyan lássunk neki?
Először is: meg kell keresni minden abszolút címhivatkozást, amely az attribútummemóriára mutat, pI.: LD HL,5800H stb. Általában a HL regiszterpárra hivatkoznak, a DE kevésbé népszerű, a BC pedig szinte elhanyagolható. A megfelelő hivatkozásokat a ROM hívás kereső programunk megfelelő átalakításával tehetjük meg. A LD HL,nn utasítás Z80 kódja: 21H. Ha megvan a hivatkozás, utána végig kell követni, mikor tölt adatot erre a helyre, Ez az adat az attribútum-byte. Kijavítása a korábbi számban közölt színtáblázat segítségével történik.
Másodszor: a színbeállítás történhet direkt töltéssel is (pI.: LD (5800H),A). Ezek keresésére és javítására ugyanazok vonatkoznak, mint az előzőekre.
Harmadszor: a bitmap címéből számítják ki a hozzátartozó attribútum címet.
Ennek két leggyakoribb változata (HL pixelcím):

LD A,H
RRA
RRA
RRA
AND 3
OR 58H
LD H,A 

avagy

LD A,H
AND 18H
RRA
RRA
RRA
OR 58H
LD H,A

Ezt a módszert leggyakrabban a szövegkiíráskor használják. Megjegyeznénk, hogy az "OR 58H" utasítás helyett az "ADD A,58H" utasítást is előszeretettel alkalmazzák. Természetesen akadnak ettől eltérő (klinikai) esetek is, de ezek a leggyakoribbak. Persze ez nem vigasztalja azt, aki mindjárt az elegyen egy ilyet fog ki.
Ennyi bevezető után lássuk konkrétan, szeretett programunk milyen módszerrel dolgozik. Először próbálkozzunk az attribútumcím számolás keresésével. A jól ismert "FIND" parancs segítségével kereshetünk egy kombinációt. Az "OR 58H" utasítás gépi kódja: F6 58. Az alábbi rutinra bukkanunk: (a teljes rutin):

65AD
65AE
65AF
65B0
65B1
6582
6583
6586
6588
6588
65BC
65BD
65BF
65C0
65C1
65C2
65C6
65C7
65C8
65CB
65CD
65CE
65CF
65D0
65D1
65D2
65D4
65D5
65D6
65D7
65D8
65D9
65DB
65DD
65DE
65E1
65E2
65E5
65E6
65E9
65EA
65EB
65ED
65EE
65F0
65F2
65F5
65F7
65F8
65FB
65FC
65FD
6600
6601
6602

E1
D9
D9
7E
23
A7
CA FB A5
FE 20
DA FC A5
D9
6F
26 00
29
29
29
ED 5B 36 5C
19
EB
2A CF 87
06 08
1A
AE
77
13
24
10 F9
7C
0F
0F
0F
3D
E6 03
F6 58
67
3A BE 87
77
21 CF 87
34
C2 AF A5
23
7E
C6 08
77
E6 18
FE 18
C2 AF A5
3E 40
77
C3 AF A5
E9
7E      
32 BE 87
23
09
C3 AF A5

POP HL
EXX
EXX
LD A,(HL)
INC HL
AND A
JP Z,A5FB
CP 20
JP C,A5FC
EXX
LD L,A
LD H,00
ADD HL,HL
ADD HL,HL
ADD HL,HL
LD DE,(5C36)
ADD HL,DE
EX DE,HL
LD HL,(87CF)
LD B,0
LD A,(DE)
XOR (HL)
LD (HL),A
INC E
INC H
DJNZ 65CD
LD A,H
RRCA
RRCA
RRCA
DEC A
AND 03
OR 58
LD H,A
LD A,(87BE)
LD HL ,A
LD HL, 87CF
INC (HL)
JP NZ,A5AF
INC HL
LD A,(HL)
ADD A, 8
LD (HL),A
AND 18
CP 18
JP NZ,A5AF
LD A,40
LD (HL),A
JP A5AF
JP (HL)
LD A,(HL)
LD (87BE),A
INC HL
EXX
JP A5AF

;visszatérési cím


;első karakter




;a SPACE
;karakternél kisebb










;egy karakter
;kiírása










;attribútumcím

;attr. byte
;attr. tárolása














;a 20H-nál kisebb
;karakter utáni byte
;attributum-byte

Talán mindenki rájött, hogy ez egy kiíratórutin (PRINT), Hívása a "CALL A5AD" utasítással történik, utána DEFB utasításokkal definiálja a szöveget. A szövegben a 20H-nál kisebb karakterek után áll egy attribútumbyte. Esetünkben a programozók az 1 kódú karaktert használták kizárólagosan. Tehát adott a következő pont: fel kell deríteni a hívásokat, majd ki kell javítani a színeket.
Célszerűnek látszik az attribútumbyte tárolására szolgáló memóriaváltozó értékadásait is megvizsgálni. És valóban, találunk is ilyet:

5216
5218

3E 43
32 BE 87

LD A,43
LD (87BE),A

Miután kijavítottuk a szubrutinhívásokat, térjünk át a másik módszerre.
Ebből is akad néhány:

389B
389E
38A1
38A4
38A6

21 00 58
11 01 58
01 FF 2F
36 47
ED B0

LD HL,5800
LD DE,5801
LD BC,02FF
LD (HL),47
LDIR

Majd egy bonyolultabb:

3B5E
3B61
3B64
3B66
3B69
3B6B
386E
3B72
3B74
3B77
3B79
3B7C
3B80
3B84
3B86
3888
3B8A
3B8C
3B8E
3B91
3B95
3B99
3B9B
3B91
3B9F
3BA1
3BA3
3BA5
3BA6
3BA7
3BA8
3BA9
3BAB
3BAC
3BAD
3BAF
3BB2
3BB6
3BB8
3BBB
3BBC
3BBF
3BC3
3BC7
3BC9
3BCB
3BCD
3BCF
3BD1
3BD4
3BD8
3BDC
3BDE
3BE0
3BE2
3BE4
3BE7
3BE8
3BEA
3BEC
3BED
3BEE
3BEF
3BF0
3BF2
3BF3
3BF4
3BF6
3BF9
3BFC
3BFF
3C01
3C03
3C06
3C09
3C0B
3C0E

21 60 58
11 61 58
36 00
01 FF 00
ED B0
21 77 58
FD 21 81 58
06 12
3A C2 87
CB 47
CA 91 7B
FD 36 00 F8
FD 36 20 46
FD 23
10 F4
1E 03
3E 47
0E 1D
C3 A3 7B
FD 36 00 47
FD 36 20 F0
FD 23
10 F4
1E 07
3E 46
0E 19
06 04
50
43
77
2C
10 FC
09
42
10 F6
21 17 59
FD 21 21 59
06 13
3A 5E F3
A7
CA D4 7B
FD 36 00 C5
FD 36 20 44
FD 23
10 F4
1E 05
3E 45
0E 1B
C3 EA 7B
FD 36 00 45
FD 36 20 C4
FD 23
10 F4
3E 44
0E 1D
11 06 00
19
1E 03
06 03
50
43
77
2C
10 FC
09
42
10 F6
21 9C 59
11 9D 59
01 A0 00
36 43
ED B0
21 57 5A
11 58 5A
36 42
01 84 00
ED B0

LD HL,5860
LD DE,5861
LD (HL),00
LD BC,00FF
LDIR
LD HL,5877
LD IY,5881
LD B,12
LD A,(87C2)
BIT 0,A
JP Z,7B91
LD (IY),F8
LD (IY+20),46
INC IY
DJNZ 3B7C
LD E,03
LD A,47
LD C,1D
JP 7BA3
LD (IY),47
LD (IY+20),F0
INC IY
DJNZ 3B91
LD E,07
LD A,46
LD C,19
LD B,04
LD D,B
LD B,E
LD (HL),A
INC L
DJNZ 3BA7
ADD HL,BC
LD B,D
DJNZ 3BA5
LD HL,5917
LD IY,5921
LD B,13
LD A,(F35E)
AND A
JP Z,7BD4
LD (IY),C5
LD (IY+20),44
INC IY
DJNZ 3BBF
LD E,05
LD A,45
LD C,1B
JP 7BEA
LD (IY),45
LD (IY+20),C4
INC IY
DJNZ 3BD4
LD A,44
LD C,1D
LD DE,0006
ADD HL,DE
LD E,03
LD B,03
LD D,B
LD B,E
LD (HL),A
INC L
DJNZ 3BEE
ADD HL,BC
LD B,D
DJNZ 3BEC
LD HL,599C
LD DE,5990
LD BC,00A0
LD (HL),43
LDIR
LD HL,5A57
LD DE,5A58
LD (HL),42
LD BC,0084
LDIR












; villógó fehér
; sárga



; fehér


; fehér
; villogó sárga



; sárga
















; villogó kék
; zöld



; kék


; kék
; villogó zöld


; zöld

A rutin első fele az opciók beállítását szolgálja. A kiválasztott opció villog. (FLASH bit beállítva) Ezt úgy tudjuk kiküszöbölni a legegyszerűbben, hogy inverz hátteret állítunk be A második fél egyszerű színbeállítást végez.
Még van egy rejtett színállítás a 6643 címen:

6643

E6 47

AND 47

A programsor környezetének megvizsgálása után nyilvánvalóbb lesz a dolog, ezt az Olvasókra bízzuk. Ezek után a MOON CRESTA már színhelyesen kezdődik, de játék közben még bőven akadnak színhibák (a SPRITE-ok). A játék így még eléggé élvezhetetlen, de úgy gondoljuk, aki idáig szorgalmasan kitartott, annak egy egyszerű ujjgyakorlat a további munka, így nem lőjük le a poént.

128K-s programok

Végezetül néhány szó a 128k SPECTRUM-ra írt programokról: Két nagy csoportra oszthatjuk a mezőnyt.
Egyrészt vannak a 48/128 fedőnevű programok. Ezek a mezei 48k-s SPECTRUM-on is működnek, általában a pályákat külön-külön töltik be. Ezek a 128-ason egy részletben betöltődnek, gyakran zenét, beszédet, plusz animációt stb. tartalmaznak. Ilyen pl. a ROBOCOP, amely zenét, valamint digitalizált (igen jó minőségű) beszédet is tartalmaz amellett, hogy minden szint a memóriában tartózkodik (nem ideiglenesen).
A másik csoport, amely kizárólag 128k-s gépen fut, esetleg 48k-s változata nem is létezik. Ezek a programok a legjobbak, mivel hosszuk többszöröse az előző csoporténak, így bonyolultabb a játék. Ezen csoport éllovasa a "WHERE TIME STOOD STILL" című program, amely bonyolultsága, grafikai kidolgozása. zenéje igazi mestermunka. Ide sorolható még a BEDLAM, THE MUNCHER, GHOULS 'n' GHOSTS, valamint a STARGLIDER 2 című program is.
Az ENTERPRISE szemszögéből az első csoport könnyen átírható, a második csoport pedig rizikós. Nehézséget az okoz, hogy míg SPECTRUM-on a teljes 128k kihasználható, addig ENTERPRISE-on az LPT-nek kell helyet hagyni. Ha nincs ennyi memória sem: akkor a reménybeli átíró makacsságán múlik a dolog. Példaképpen: az említett WHERE TIME STODD STILL programban nem volt 200 byte szabad hely sem, de azért...
A 128k SPECTRUM memóriakezeléséről már volt szó. Ezt úgy lehet átírni, hogy minden SPECTRUM szegmenshez hozzárendelünk egy ENTERPRISE szegmenst, a

LD BC,7FFDH
LD A,x
OUT (C),A

utasításokat pedig átírjuk egy

LD A,y
OUT (0B3H),A

utasításcsoportra. x az eredeti, y a módosított szegmensszám.

A zene átírása már keményebb dió. Az AY-3-8912 regisztereinek leírása a SINCLAIR SPECTRUM JÁTÉK ÉS PROGRAM V. c. kötetében található (LSI ATSz. 1988.). A feladat az hogy olyan szubrutint készítsünk, amely a megfelelő AY és DAVE regisztereket egymáshoz rendeli. Ezt a problémát még egyedüli és üdvözítő módon nem sikerült megoldani.
A problémák:

Nos, ennyi lett volna ez a bűvös tudomány. Ha valaki végigolvasott minden részt, attól még nem biztos, hogy képes is önállóan végrehajtani egy ilyen műveletet (sőt!), de a kiindulás talán világosabb lett. Akit hidegen hagyott az a perspektíva, hogy saját maga írhat át programokat, esetleg az egyes rutinok programozási módszereibol okulhatott valamit, hiszen eléggé átfogó jelleggel kellett használni mind a gépet, mind az operációs rendszert.
Utolsó gondolatként annyit, hogy reményeink szerint sokan kaptak kedvet a témához, és futószalagon szállítják a jobbnál-jobb átiratokat. Mivel eredeti ENTERPRISE programok már nemigen készülnek és sok embernek van ilyen gépe, napjainkban egyre nagyobb szerepe lesz az amatőröknek.

Zozosoft instrukciói a  ZX Spectrum programok átírásáról

Ahogy a cikkben is írva van, az első lépés a program fájljainak megszerzése. A cikkben leírt program anno bekerült a Spectrum Emulátor ROM-jába is, SCOPY néven. Viszont manapság nem túl valószínű, hogy valaki tényleg kazettáról akarna Spectrum programot beolvasni, sokkal valószínűbb, hogy a netről szerzi be az ember a Spectrum progit, .TAP vagy .TZX formában. Ezért a nemrég elkészült 4.1-es verziójú Emulátor ROM nem csak be tudja tölteni ezeket, hanem az SCOPY is ki lett egészítve ezeknek a kezelésével. Így néz ki a Bumpy szétszedése:

Mint az Emulátoron való futtatáshoz, itt is célszerűbb a .TAP verzió választása, ez mentes a spéci betöltőktől és egyéb trükkös védelmektől.

Spectrumon a legtöbb játék egy BASIC betöltővel kezdődik, így van ez jelen esetben is. Tehát első lépésben ennek tartalmát kell megtudnunk. Erre is kitűnően használható az Emulátor, a programot MERGE "" paranccsal töltsük be, így nem indul el egyből, ki lehet listázni:

Ezután már tudjuk a program betöltési címét (25000) és indítási címét (43900).

Ezután jön a betöltő megszerkesztése, ismét a már jól ismert betöltőmet használtam fel. A memória lefoglalás, ennek függvényében videocím kiszámítás, a rendszerhez való visszatérést biztosító HIBA eljárás a szokásos, "100% EXOS kompatibilis"
Amit most megemlítenék, hogy az elmúlt félórában tovább fejlesztettem memóriakezelést, így most már nemcsak, hogy EXOS 2.0 kompatibilis, hanem RAM bővítés nélküli EP64-en is fut a program! Gyakorlati értelme nincs sok, de szeretem a kihívásokat, a vajon hogyan lehetne megoldani problémákat. De hátha majd előkerül a világból egy EP64 tulajdonos, és nagyon fog örülni, hogy végre egy játék ami az ő gépén is fut. Gyakorlatilag a hivatalosan kiadott néhány játékon kívül nincs egyetlen program se ami menne EP64-en.
Egyik ok, a közvetlen szegmenscímek használata, ami megakadályozza azt is, hogy felbővített EP64-en fussanak a programok (kivéve, ha F8-FB címeken is van bővítés). Másik ok, hogy nincs elég RAM egy 64K-s gépben, ami első hallásra elég furcsa, hiszen egy 48K-s program miért ne férne el egy 64K-s gépben? Egy átlag Spectrum átírat 4 szegmenst használ: egy videó szegmens az alsó 16K Spectrum memóriának, amiben található a képernyő memória is. Két másik szegmenst a felső 32K Spectrum memóriának, és kell még egy videó szegmens az LPT tábla számára. Viszont egy 64K-s gépen csak 2 szabad szegmens van... a másik kettő a nullás lap ill. a rendszerszegmens céljára van felhasználva.
Azt már eddig is tudta a betöltőm, hogy az LPT tábla akár lehet megosztott szegmensben is, tehát ha van elég hely benne, a rendszerszegmens elejére kerül az LPT tábla, így máris megspóroltunk egy szegmenst. De még mindig kéne egy... Egyszerű a megoldás: a nullás lapról tegyük át az EXOS cuccait, no meg a saját programunkat a rendszerszegmensbe, állítsuk be a rendszerszegmenst nullás lapnak, és máris miénk az eddigi nullás lap szegmens!
Gyakorlatban így működik ez a fejlesztett betöltő:

Ha a 3. szegmens lefoglalásánál EP64 problémával találkozik, akkor a következő történik:

Ennek megfelelően módosult egy kicsit az LPT készítő rutin is, hogy az előre megadott címen kezdje készíteni az LPT szegmensben az LPT-t. Ez normál esetben nulla, ha EP64 módban fut a program akkor lesz 800H. Természetesen ezzel módosult egy kicsit az LPT cím kiadása is a NICK-nek, hiszen így a 8-11-es címbitekkel is kell foglalkozni.
A HIBA eljárás is bővítve lett, ha lett eltárolva nulláslap szegmensszám, akkor kilépés előtt helyreállítja azt, visszamásolva az első 800H bájtot. Ily módon még EP64 módban futva is megőriztük a rendszer teljes épségét, töltési hiba, vagy meleg reset esetén szépen kilép az EP logóhoz a program!
Kisebb módosítások voltak az EXOS 2.0 kompatibilitáshoz (Amit már a CPC betöltőmben is megcsináltam), a kép alján lévő státuszsor az EXOS-tól lesz átvéve, ill kilépéskor a rendszerszegmensből lesz kiolvasva a visszaállítandó EXOS LPT címe.

Miután sikerült a szükséges memóriát megszerezni, elkészíti az LPT táblát (részletesen lásd az SpV cikkben), majd betölti az SCR fájlt, ami az SCOPY-s kicsomagolás után kapott BUMPY.3FF átnevezésével készült. A kép betöltése után átkonvertája az attribútum terület minden egyes bájtját EP formátumra. Egy bájt konvertálása a következő módon történik: egy 256 elemű táblázatra rácímezve (H a cím felső 8 bitje, L a konvertálandó attributúm) kiolvasható a Spectrumos attribútum bájt EP-s megfelelője, amire le lesz cserélve az adott bájt.
Ez a táblázat az Emulátor új ROM-jának fejlesztésekor készült, ebben benne van az is, hogy az elvileg villogó kombinációk inverzek legyenek, legalább így különbözve a FLASH nélküli azonos kombinációtól. Az Emulátor eredeti programja, meg sok átírat nem foglalkozik ezzel a problémával, így akad jó pár játék, ahol nem tudni, hol áll a menüben a kurzor, mert az eredetileg villogna... ezzel a módszerrel inverz lesz a kurzor, és így már használható lesz.
Hogy a táblázatra címezni tudjunk, annak xx00H címen kell kezdődni. Eredetileg úgy működött a betöltőm, hogy a programban lévő táblázatot 1000H címre másolta induláskor, és itt volt használva. Most az EP64 kompatibilitás miatt helyspórolás okán lekerült 100H-ra. Így viszont induláskor hiányzik az első három bájt, mivel ott a táblázatott átugró JP található, így ez a 3 bájt az első konvertálás előtt lesz kitöltve.
Miután a betöltő kép attribútumai át lettek konvertálva, átkapcsolunk a Spectrumos LPT-re, ezután következik a PRG betöltése (ami eredetileg a BUMPY.5FF fájl volt).
A sikeres betöltés után jön még egy nagyon fontos dolog. Mivel a letöltött .TAP fájl mellett rögtön ott volt egy örökélet POKE is, így ezt is beletettem, hátha valaki élni akar ezzel a lehetőséggel. A kérdést a státuszsorba kiírva tesszük fel, majd az Y és N billentyűk figyelése következik végtelen ciklusban. Y válasz esetén elvégezzük a POKE-t, és ezután jöhet a program indítása. (Mellesleg ennek a kérdésnek az is a mellékhatása, hogy floppyról töltve is meg lehet nézni alaposan a betöltő képet, nem tűnik el egyből. Ezért más programoknál ha nincs is ilyen kérdés, akkor is be szoktam rakni egy billentyűre várakozást.)

Visszatérve a Bumpy átírásához: miután van remek betöltőnk, el is indul a program, persze a menü kiírásánál többet nem igen csinál, hiszen nincs még billentyűfigyelés se... A CPC programoknál azt láthatjuk, hogy leginkább ROM hívásokat használnak, ami nem véletlen, hiszen elég bonyolultan lehet közvetlenül programozni a CPC HW-t (pl. a billentyűzetlekérdezés is hasonlóan bonyolult, mint ahogy a hangchip regisztereit lehet kezelni).
Spectrumon jóval egyszerűbben kezelhető a HW, így a játékok nagy része ezt a módszert alkalmazza billentyű, joystick lekérdezésre, hang generálásra. Így nem működik az a módszer, amit a Popup esetén láttunk, hogy a betöltőben elkészítve a megfelelő ROM rutinok szimulációját, gyakorlatilag az eredeti program fájlokhoz hozzá se nyúlva működőképes lesz a program. Meg kell keresni, és át kell írni az ilyen közvetlen HW hívatkozásokat.
Kezdjük az irányítással, ehhez a FEH prot olvasásokat kell megtalálnuk. A keresgélést FENAS-ban célszerű végezni, így a helyére tölthető a PRG fájl, Bumpy.prg esetén az 61A8H-F8D3H területet jelent. (Talán nem véletlen, hogy Moonlight-ék úgy alkották meg a FENAS-t, hogy 4000h-FFFFh-ig szabad a memória Így erre a célra sokkal alkalmasabb a FENAS-t használni, hiszen így az eredeti helyére tölthetőek a program darabok. A disassembler rész is sokkal használhatóbb, mivel nem egy gyorsan elszaladó listát látunk, hanem a fel/le gombokkal tudunk mozogni a programban.)
A program az AB7CH címen indul. Szerencsére ez esetben nincsenek olyan trükkös átkódolós védelmek, mint az SpV-ben ismertetett Moon Cresta esetén, (persze más programnál simán bele lehet futni ilyesmibe), így egyből lehet a lényegre koncentrálni. FEH portolvasást egy helyen találni:

A rutin első része sorban lekérdezi az összes billentyű sort, és eltárolja. A ciklus után van még egy igen érdekes IN A,(0DFH)! Ilyen port elvileg nem is létezik Spectrumon. A megfejtés: A legtöbb Spectrum HW nem alkalmaz teljes címdekódolást (így meg lehet pár IC-t spórolni), ezért az egyes I/O portok több címen is láthatóak. Pl. az ULA 0FEH portja az összes páros című porton... Jelen esetben a Kempston típusú joystick illesztő lekérdezésről van szó, ami normál esetben az 1FH porton történik. Még szerencse, hogy közvetlenül a billentyű lekérdezés mellett van, különben órákig lehetett volna keresgélni, hogy hol is kérdezi le, amikor nincs 1FH port hivatkozás.

A program módosításához már készen állnak a betöltőben a kész rutinok, az elv hasonló az SpV-ben leírtakhoz. A fontos rutinok címeit én a nem használt RST rutin belépési pontokra teszem, így 3 bájtos CALL helyett elég egy bájtos RST utasítás a meghíváshoz, így mindenhova befér.
Jelen esetben minket a PORTFE rutin érdekel elsőként, ezt szint a Spectrum Emulátor új ROM-jához fejlesztettem ki eredetileg. Ez nemcsak a FEH port olvasását tudja emulálni, hanem annak írását is, azaz a hang generálást, ill. a keretszín (konvertált tehát színhelyes beállítását is).
Paraméterként felhasználja az RST utasítás utáni bájtot is, 0DBH jelenti az IN A-t, 0D3H az OUT A-t, 0EDH az IN A,(C)-t, de szükség esetén más kombinációk is legyárthatók (IN B,(C), stb). Beolvasásnál a megadott sor(okat) olvassa be, és adja vissza, teljesen Spectrumos módon. A számbillentyűknél be van keverve a dologba az Internal+ALT is, a Sinclar joystick illesztőt szimulálva. Az Emulátoros verzióban az External joy-ok is itt voltak bekeverve, az átírásos verzióban azokat a Kempston illesztő szimulálására tartogatjuk, JOY névre hallgató rutinban.
Bumpy indulásakor a PORTFE az RST 28H-ra kerül a betöltőben, a JOY pedig az RST 8-ra. Így csak annyit kell tenni, hogy B423H címen található IN A,(0FEH) utasítást kicseréljük:

B423
B424

EF
DB

RST 28H
0DBH

A joystick olvasó IN A,(0DFH)-t pedig:

B42B
B42C

CF
00

RST 08H
NOP

Ezekután már lehet is játszani, csak hang nincs még, és itt-ott színhibás a program.

Hang
Következik a hang: erre sajnos nem túl sok szót vesztegettek a SpV cikkben. A Moon Cresta a Spectrum ROM hangrutinját használta, amelynek EP-re módosított változatát berakták a betöltőbe BEEP néven. És annyival elintézték az ügyet, hogy a ROM rutin hívását cseréljük ki ennek a rutinnak a hívására.
Először is itt volt egy nagyon csúnya nyomdahiba!!! Az ott közölt rutinban az 0A7H portra küldik ki az adatot, ami teljesen értelmetlen! A helyes az 0A8H vagy 0ACH! (0-ás hangcsatorna bal ill. jobb hangerő). Ennek a nyomdahibának köszönhetően elég sok néma átírat került forgalomba, mivel a hibás 0A7H címet használták... jó pár ilyet ki is javítottam már.
De mi is a helyzet a közvetlen port piszkálással történő zenéléssel Spectrumon? Hiszen a legtöbb játék ezt használja. Itt szintén a 0FEH port kap szerepet, ezúttal OUT utasítással kezelve. Az ide írt adat 0-2 bitje a keretszínt határozza meg. A 3. bit a magnókimenetre vonatkozik, ez minket nem érdekel, a 4. bit jelképezi pedig a ZX Spectrum összes zenei képességét 1 bites D/A kimenet formájában.
Először tehát meg kell keresnünk az összes 0FEH portra vonatkozó utasítást, és utána kezdeni velük valamit. A betöltő induláskor D/A módba kapcsolja a DAVE 0-ás hangcsatornáját, ezután az előbb emlegetett portok segítségével tudunk hangot generálni. Sok átiratban egyszerűen csak kicserélik az OUT (0FEH),A utasításokat OUT (0A8H),A-ra (vagy 0ACH-ra) ami végül is működő megoldás, de van 1-2 probléma vele. Egyrészt nem foglalkozik a keretszín problémájával, másrészt mivel csak az egyik hangerőt állítja a DAVE-ben, így ha sztereó kimeneten át hallgatjuk kedvenc EP-nket, akkor csak az egyik oldal fog szólni, ami elég zavaró, esetleg a programozásban kevésbé jártas felhasználó elkezdi keresni a kontaktos kábelt, hogy miért nem szól a másik oldal.
A már emlegetett PORTFE rutinunk mivel a Spectrum Emulátorhoz készült, OUT esetén természetesen kezeli a keretszín problémáját is, és persze a hangot is mindkét oldalra adja ki. Egyetlen probléma, hogy ez így elég sok utasításból áll, ami intenzívebb hangpiszkálásnál észrevehető lassulást okozhat. Köztes megoldásként készült a CSAKOUT nevű rutin, ami egyrészt nincs beágyazva az általános PORTFE rutinba, így már egy csomó utasítást megspóroltunk, másrészt a keretszínnel se foglalkozik. Magyarán egy OUT (0A8H) és egy OUT (0ACH) utasítás az egész.
A Bumpy esetén először az általános rutint alkalmaztam, majd úgy találtam nem az igazi a hang, viszont a keret mindig fekete, így végül a CSAKOUT módszer lett a végleges.
OUT (0FEH) utasítás a következő címeken volt a Bumpy-ban: B485H, EC4AH, ED1BH, EF34H, F514H, F525H, F53BH, F550H, F569H, F59CH. Itt mindenütt az

OUT (0FEH),A

helyett:

C7
00

RST 00H
NOP

utasításokra lett átírva. Ezután már hang is van. A Bumpy-val idáig eljutni a .TAP letöltésétől számítva kb. 10 perc volt.

Attribútumok
Az átírás utolsó fázisa pedig az attribútumok kijavítása... ez a legnehezebb, legidőigényesebb művelet.
Itt nincs semmilyen általános módszer, minden programban más és más módszert alkalmaznak. A felderítésre a SpV cikk 9. része ad útmutatást. A lényeg az, hogy az 5800H-5AFFH közti memória területekre irányuló műveleteket kell figyelni.
Ahol fix érték beírását találjuk, ott kinézzük a konvertáló táblánkból (ami a betöltő forrászszövegének elején található) a megfelelő értéket, és kijavítjuk.
Ennél sokkal gyakoribb, az amikor egy regiszterben megkapott érték kerül beírásra, leggyakrabban egy LD (HL),A utasítás formájában. Itt a legegyszerűbb kicserélni ezt az utasítást egy olyan rutin meghívására, ami már a konvertált értéket írja be. Erre szolgál a KONV nevezetű rutin a betöltőben, ami RST 10H-re kerül, tehát a megtalált ilyen LD (HL),A utasításokat RST 10H-ra kell cserélni.
Az adott programtól függően persze más módszerek is előfordulnak, a KONV alapján könnyen legyárthatóak. Pl. a BUMPY esetén előfordul LD (HL),C variáció, ez KONV2 néven található meg a betöltőben, és az RST18H-ra kerül.
Szintén nagyon gyakori, még az LDIR, LDI (néha LDDR, LDD) alkalmazása, általában akkor amikor a játék valamely előre elkészített grafikai eleme (falak, tárgyak,stb) kerül a képernyő memóriába másolásra.
Bumpy esetén LDI fordul elő, ez KONV4 néven kerül megvalósításra, ez az RST 20H-ra kerül. Ha a KONV4-ben a kipontosveszőzött JR utasítást visszatesszük, akkor LDIR-t kapunk, az INC HL, INC DE utasítások DEC-re cseréjével pedig az LDD, LDDR állítható elő.
Konkrétan:

B471
B473
B476
B479
B47C
B47D

 LD A,07H
  LD HL,5800H
  LD DE,5801H
  LD BC,2FFH
  LD (HL),A
  LDIR

Könnyen felismerhető, hogy ez egy attribútum terület törlés, ráadássul 7-es értékkel, ami EP-n is 7-es, így ezzel nincs további dolgunk.

B4F8
B4FB
B4FD
B4FE
B500
B501
B502
B503
B504
B505
B508

LD HL,5800H
LD B,18H
PUSH BC
LD (HL),06H
INC HL
PUSH HL
POP DE
INC DE
LD (HL),A
LD BC,1CH
LDIR

Az LD (HL),06H szintén maradhat, viszont az LD (HL),A-t ki kell cserélni egy RST10H-ra
B6F1-en meg van egy LD DE,5803H és utána egy nagy rakás LDI, amit most lusta vagyok ide bemásolni ezeket mind RST 20H-ra kellett kicserélni.
F0D8-on pedig szintén egy attributum terület törlés megadott értékkel, itt az F0E4-en lévő LD (HL),A-t kell RST 10H-ra cserélni.

E799
E79C
E79D

LD DE,5800H
ADD HL,DE
LD (HL),C

Ezt az LD (HL),C-t kell RST 18H-ra cserélni, E7A8-on ven még egy.
E2E4-en van még egy LD DE,5800H, ADD HL,DE című rész, amihez végül E30E címen tartozik egy LD (HL),06H. 6-os attributum tehát lehet békén hagyni...

Ezekután már egész jól ment a program, csak a felvehető tárgyak voltak makacsul világoszöld alapúak...
Itt kezdődött kb 3-4 órás szívás amíg próbáltam újabb helyeket találni, amik az attributum területeket piszkálják...
Végül rájöttem, hogy az előbb átugrott E30EH címen lévő LD (HL),n utasítás a bűnös!
Igaz, hogy ott alapban 6-van amit nem kell bántani, de itt látható egy szép példája a Neumanni elvek alkalmazásának, miszerint a program és adat ugyanabban a memóriában tárolódik. Jelesül, hogy itt egy önmagát módosító programról van szó!

E2E4
E2E7
E2E8
E2E9
....
E30E

LD DE,5800H
ADD HL,DE
LD A,C
LD (0E30FH),A

LD (HL),06H

Na itt a bűnös! Az E2E9H-en lévő utasítás írja át az E30EH címen lévő LD paraméterét!
Ennek megvalósítására készült egy E30F nevű rutin a betöltőben, amely szabad RST hiányában az 0005H címre kerül, és az E2E9H az LD utasítás CALL 0005H utasításra lett cserélve.

A fakó szín problémáról:
Spectrumon 8 szín van, plusz van egy BRIGHT bit, így megkapjuk ezek fényes változatát, azaz még 7 színt (fényes fekete nincs).
Enterprise-on 8 színt szabadon választhatunk, 8 színt csak egyben a FIXBIAS által.

Hova állítsuk a FIXBIAS-t?
Sok program esetén (gondolom az SPV-t követve) 0-ra állítják. (illetve van, hogy nem is állítják, így hidegindítás után jól fut a program, mivel 0 az alapérték, de ha már valami más program átállította, akkor előjönnek színhibák). Ez esetben az a jó, hogy FIXBIAS-ban lesz fekete, és a palettában is beállítunk feketét, így lekezeltük azt, hogy csak egyféle fekete van.
A rossz viszont az, hogy a fekete mellé kapott másik szín túl sötét még normál Spectrum színeknek is. És ha nem akarunk túl nagy kontraszt különbséget, akkor a palettába választott színek is sötétebbek lesznek mint a fényes Spectrum színek. Ez különösen a fehérnél szokott feltűnni.
Van még egy nagy hiba az SPV-ben: "A már említett programunk a FIXBIAS regiszterbe 0-t tölt. Az így előálló színkombinációk megfelelnek a SPECTRUM BRIGHT színeknek."
Na ezt nagyon nem kellett volna! Ezek a színek normálnak is sötétek, nemhogy fényesnek... Ha valaki ebből indul ki, akkor az eredeti fényes színek lesznek nagyon sötétek, a normálok meg a fényesnél világosabb de sötétek!
Én onnan indultam ki, hogy a fehér az legyen fehér! Vagyis 255-ös FIXBIAS. Itt a fehér mellé kötelezően kapott színek egész jól megfelelnek a Spectrum fényes színeinek. Emellé már gyerekjáték a palettába összeválogatni közepes fényerejű színeket Spectrum normál színeknek.
Egyedüli probléma, hogy a BIAS-ban kapunk egy fényes feketét is, tehát konvertáláskor ügyelni kell, hogy a fényes fekete normál feketére legyen konvertálva (de néha akár ki is lehet használni ezt a plusz színt is!). Összehasonlításképpen néhány paletta:

Spectrum
Spectrum Világ
BIAS=0,
nagy kontraszt
Wec Le Mans
(Attus)
ZozoSoft

Az Enterprise teljes színpalettája (a bal oldali hasábban a BIAS):

Itt egy kis BASIC program ami egy tömbben összerendeli a Spectrum színeket az EP színekkel. EP-n olyan palettát feltételezve, ahol a 8 szín megfelel sorban a normál Spectrum színeknek, a FIXBIAS pedig a fényes színeknek, a fényes fekete sima feketéhez lesz rendelve. A második részében pedig minden lehetséges attributum kombinációhoz kiszámolja az EP megfelelőt. A FLASH-t invertálással helyettesíti. Ezt a táblázatot fájlba menti.
Ez a tábla van használva a Spectrum Emulátor programjában, ill. az átirataimban is.

SPECCOL.BAS

Menü szöveg átírása már rutin munka, és kész is volt a Bumpy.

István instrukciói a 128K-s hangok átírásáról

Az SPV cikke csak érintőlegesen tesz csak említést a 128K-s hangok megvalósításáról. Az egyik kardinális problémaként a hardware burkológörbéket említi.
A burkológörbe megszakításból emulálható. Természetesen ez elfogyaszt némi CPU időt, és nagyobb burkológörbe frekvencia esetén a minőség sem tökéletes, de gyakran elfogadható eredményt lehet elérni. CPC átiratoknál (melyben szintén az AY chip felelős a hang előállításáért) jól használható a 300 Hz-es megszakítás, de ha fontos a minőség, akkor CPC és Spectrum átiratnál is lehet 1 kHz-es megszakításból emulálni a burkológörbét (ilyenkor kisebb problémát jelent, ha a játék HALT utasításokat használ időzítésre) - így még a Wec Le Mans motorhangja is, ha nem is tökéletes, de azért felismerhető. Az is megoldható, hogy ne minden 1 kHz-es megszakítás frissítse a burkológörbét, hanem csak például minden negyedik (rosszabb minőség, de kisebb CPU igény).
Ha egy csatornán egyszerre szól(na) a zaj és a tiszta hang, ezt úgy oldottam meg, hogy fordításkor választhatóan csak négyszögjel vagy csak zaj legyen ilyenkor, vagy négyszögjel valamilyen torzítással.
AY emuláció ismertetése előtt nézzük át röviden az AY regisztereit:

0:
0.0000
4:
0.0423
8:
0.1691
12:
0.5704
1:
0.0137
5:
0.0618
9:
0.2647
13:
0.6873
2:
0.0205
6:
0.0847
10:
0.3527
14:
0.8482
3:
0.0291
7:
0.1369
11:
0.4499
15:
1.0000

Amint látható, a 0-5 regiszterek nagyjából megfelelnek a DAVE A0h-A5h portjainak, de a DAVE négyszögjel frekvenciája eltérő módon számítható:

125000 / (N + 1) (ha a BFh I/O port 1. bitje 0)
83333.33 / (N + 1) (ha a BFh I/O port 1. bitje 1)

Ezek az értékek 4 MHz-es gépre érvényesek, egyébként az órajellel arányosan nagyobbak.

Zajgenerátornak felhasználható a DAVE első három csatornája is 17 bites polinom számlálóval (ehhez az A6h portra 10h-t kell írni, ami felcseréli a 7 és 17 bites számlálót, azaz így az 1-3. csatorna használhatja a 17 bites, a 4. (nem használt) csatorna pedig a 7 bites számlálót). Figyelni kell azonban arra, hogy a zajgenerátort ez a négyszögjel frekvenciájának a kétszeresével mintavételezi, azaz a fel- és lefutó élnél is.
Ezek alapján a Spectrum és CPC frekvencia értékek így közelíthetők:

Spectrum négyszögjel: N * 1.125 - 1
Spectrum zaj: N * 2.25 - 1
CPC négyszögjel: N * 2 - 1
CPC zaj: N * 4 - 1

A Spectrumnál az 1.125 ugyan nem egészen pontos, de az eltérés kisebb, mint 0.25%, és ez az arány egyszerűen számítható néhány Z80 utasítással.

Spectrum négyszögjel frekvencia konverzió (HL AL):












.l1:
.l3:
sra b
rra
sra b
rra
adc a,l
ld l, a
dec hl
ld a, b
adc a,h
cp 10h
jr nc,.l3
...
inc l
inc a
jr z,.l1
ld l, 0ffh
ld a, 0fh
jp .l1










; overflow?

Spectrum zaj frekvencia konverzió (A A):

  cp 1
adc a, 0
ld h, a
rra
sla h
rra
adc a,h
dec a
 

Ezek figyelnek a túlcsordulásra, a "speciális" N=0 esetre, ami azonos az N=1-el, és még arra is, hogy az eredmény ne lefelé legyen kerekítve, hanem a pontos (tört) értékhez a legközelebb legyen. Mindkét esetben a kód feltételezi, hogy a felső, AY által nem támogatott bitek 0-ra vannak állítva.

A CPC jóval egyszerűbb. Négyszögjel (HL AL):






.l1:
.l3:

add hl,hl
dec hl
ld a,h
cp 10h
jr nc,.l3
...
inc l
inc a
jr z,.l1
ld l,0ffh
ld a,0fh
jp .l1




; overflow?

Ez ugyan nem egészen jó, mert a 0 frekvenciát 0-ra konvertálja, pedig 1-re kellene. De mivel normál esetben (torzítás nélkül) egyik sem hallható, ez talán nem jelent komolyabb problémát. De egyszerűen javítható is az INC L helyére LD L, 1-et írva.

CPC zaj (A A):

 

cp 1
adc a,0
add a,a
add a,a
dec a
 

A hangerőt egyszerű táblázattal lehet konvertálni (de ha nem fontos, hogy pontos legyen, megfelelhet a 4-el való szorzás is):

  defb 0,1,2,3,4,5,6,9
defb 12,17,22,28,36,44,53,63

A hangerő táblázatot több helyen lehet látni például különböző PC-s CPC és Spectrum emulátorokban (kisebb eltérésekkel, az alkatrészek szórása és mérési pontatlanságok miatt), de talán az eredeti AY dokumentáció is említi, hogy nem lineáris, csak nem jó értékeket adtak meg. Az itt látható táblázat a FUSE Spectrum emulátorból van.

Vissza