Gépikód kezdőknek

File-név: GEPIKOD.BAS
Program neve: Gépikód Kezdőknek 6.0
1985 - Entersoft Ltd.
Oktató program
Bevezetés
1. A központi egység és a memória
2. A szimulátor program használata, első lépések a gépi kódú programozásban
3. További gyakorlatok a szimulátorral
4. Logikai utasítások: AND, OR, XOR
5. Jelzőbiket. Új utasítások: CP, RRA, RLA, SRA, SLA
6. A verem. PUSH és POP, CALL és RET
7. Feltételes ugrások, indirekt címzés
8. A két hátralévő parancs: OUT és DATA. Az assembler képernyő.
9. Vezérlő kódok
10. A P regiszter
11. Gyors futtatás, töltés és mentés, listázás
12. A Z80-as mikroprocesszor
Függelék
A. Decimális számok (10-es számrendszer)
B. Bináris számok (kettes számrendszer)
C. Hexadecimális számok (16-os számrendszer)
D. A szimulátor használatának összefoglalása

Bevezetés

A gépi kódú programozás élvezhető és igen hatékony dolog. Ugyanakkor egy sok energiát igénybe vevő szakterülete a számítástechnikának. E program feladata, hogy látványos képernyővel segítse megértését, miközben gépi kódú programot fejlesztünk és futtatunk. A program egy Z80-ashoz nagyon hasonló (de annál egyszerűbb) processzor működését szimulálja. Fontos tudni, hogy amikor a programban beírunk egy Z80-as "programot" a szimulátor segítségével, és elkezdi a szimulátor azt futtatni, akkor nem a valódi processzoron fut a program, hanem egy emulátoron. Ahhoz, hogy közvetlenül a Z80-as processzoron futtassuk gépi kódú programjainkat, egy assembler programra van szükségünk.

1. A központi egység és a memória

Két igen fontos alkotórésszel kezdjük az ismerkedést:

  1. A memória
  2. A központi egység


1. ábra

A memóriát úgy lehet ábrázolni, mint egy galambdúcot ahol számokat lehet tárolni. A mi szimulátorunkban 256 ilyen galambdúc van, melyeket memória rekeszeknek nevezünk. (Az igazi számítógépeknek ennél sokkal több rekeszük van.)
A galambdúcok 0-tól 255-ig meg vannak számozva. A galambdúcon lévő számok címek, angolul "adress"-nek nevezzük. Vigyázni kell arra, hogy mindig különbséget tudjunk tenni a memóriarekesz címe és annak tartalma között Példaképp nézzük az 1. ábrát!
A "7"-es szám abban a memóriarekeszben van tárolva, melynek címe 255. Így ezen ábrán a következőket látjuk:

Cím
Tartalom
0
21
1
123
255
7

A központi egység együttműködik a memóriával. Számokat tud tenni egy galambdúcba, ki is tud onnan venni számokat és dolgozni tud velük (például aritmetikai műveleteket végez rajtuk). Amikor egy szám érkezik a központi egységhez, akkor egy belső tárolórészen lesz elhelyezve, Ezen belső tárolórekeszeknek speciális nevük van: regiszterek. A valódi Z80-as processzornak 22 darab ilyen belső regisztere van, de az egyszerűség kedvéért ez a szimulátor csak 6 regisztert használ. A programozó szemszögéből a központi egység regiszterei két csoportra oszthatók:

  1. Azok, melyekkel a programozó dolgozik a programjában
  2. azok, amelyeket maga a központi egység használ működéséhez

A szimulátorban az első csoportot a következő regiszterek reprezentálják:

A második csoportba a következők tartoznak:

A regiszterek nevei valószínűleg még érthetetlenek. Részletes leírásuk később következik. A szimulátor tartalmaz még egy ún. lapregisztert. Ennek segítségével 256 byte-nál hosszabb "programokat" is írhatunk. További részletekkel a 10-es fejezetben találkozunk, ebben a pillanatban erre nincs szükségünk.
Most már van valami fogalmunk a memória és a központi egység kapcsolatáról. Ezután kicsit részletesebben foglalkozunk ezekkel, ehhez viszont szükség lesz a 2-es és a 16-os számrendszer ismeretére. Akinek ezzel problémája van, az nézze át az A függeléket.

2. A szimulátor program használata, első lépések a gépi kódú programozásban

Ezt a programot azért tervezték, hogy segítse megérteni a gépi kódú programozást, párbeszédes rendszer segítségével. Egy nagyon egyszerű példával kezdjük. Először is töltsük be a programot a számítógépbe. Miután elindult a program, egy menü jelenik meg. Tekintsük át a menüpontokat:

  • A - ASSEMBLE - Itt tudjuk "programjainkat" elkészíteni.
  • R - RUN - Az elkészített "programot" tudjuk lefuttatni.
  • O - Load - elmentett program betöltése.
  • S - SAVE - program elmentése háttértárolóra
  • X - RESTART - program törlése, a szimulátor alaphelyzetbe állítása
  • L - LIST program listázása.
  • P - PRINTER LIST - program nyomtatóra listzása.
  • T - BINARIS / HEX - átváltás a decimális / hexadecimális üzemmódok között. A menü alatt láthatjuk az aktuális üzemmódot.

Először nyomjuk meg a "T"-t, s így decimális üzemmódba kerül a program. Ezután kezdjük el "programunk" bevitelét! Ehhez nyomjuk meg az "A" billentyűt, aminek a hatására a következőket látjuk:

Ne ijedjünk meg, attól, hogy szinte semmit nem értünk a látott képernyőből, Később minden világos lesz. A képernyő jobb oldalán -segítség képen- az alkalmazható utasítások listája látható, bal oldalon felül a paraméterek szintaktikája. A program most programunk kezdőcímét kérdezi tőlünk, vagyis azt, hogy a program hányadik memóriarekeszben kezdődjön.
Adjuk meg most a 0-át (0-s memóriarekesz)! Ekkor elkezdhetjük beírni a programunkat. Ekkor pontosan a következőt gépeljük be:

LD A,123

Ezután természetesen ENTER kell. Figyeljünk arra, hogy az LD és az A között szóköz van! Ha bármilyen hibát vétünk gépelés közben, a törlő billentyűt a megszokott módon használhatjuk.
Ha befejeztük a gépelést, az ENTER megnyomásával új sort kezdhetünk, ilyenkor az ENTER ismételt megnyomásával visszaléphetünk a menübe. Tegyük most ezt!

Ezzel befejeztük első gépi kódú programunkat. Igaz rövid, de működtethető. Ha lefuttatjuk, a 123-as szám töltődik az akkumulátor regiszterbe. Futtatni akarjuk a programunkat, ezért a menüből az "R" billentyű megnyomásával lépjünk be a program futtatása menüpontba. A következő kérdés a programunk futási sebességére irányul. Választhatunk lépésenkénti végrehajtást (egy billentyűlenyomásra egy utasítás hajtódik végre, ehhez a 0-át kell megnyomnunk), vagy különböző sebességű folyamatos végrehajtást (1-255) . Az "R" megnyomásával "valós időben", késleltetés nélkül lefut a programunk, ilyenkor nincs is értelme a memória, regiszterek állapotának kijelzésének, (olyan gyorsan lefut a program), ezért csak a képernyőre kerülő információkat láthatjuk. A program futását az ENTER billentyűvel állíthatjuk le.
Most a "0" sebességet javasoljuk. A következő képernyő jelenik meg:

Program futása előtt
Program futása után

A bal oldalon a verem és a memória állapota, jobb oldalon a regiszterek állapota követhető nyomon. A FLAGS kijelző a program által kezelt két jelzőbit (ZERO, CARRY) értékét mutatja. Jobb oldalon felül láthatunk egy kijelzőt, itt jelennek meg a programunk által a "képernyőre" kerülő üzenetek.
A következőt gépeltük be: "LD A,123"
Ez egy utasítás a számítógép részére, hogy tegye be az akkumulátorba a 123-as számot. Az "LD A" részét az utasításnak "mnemonik"-nak nevezzük. Az "LD" a következő angol szöveg rövidítése: Load the accumulator with a number" azaz, "tölts egy számot az akkumulátorba". Azt a számot, amelyet az akkumulátor regiszterben kell tárolni "operandus"-nak nevezik. Tehát a következőképpen néz ki az utasítás:

Mnemonik Operandus
LD A 123

Az ábrán látható, hogy a 123-asa szám valóban bekerült az akkumulátorba. A következőket láthatjuk:

123 01111011
A

A 01111011 a 123-as szám bináris alakja. A számítógép az összes számot bináris formában kezeli. Ebből következik a következő témánk:

BIT-ek BÁJT-ok
A bit értéke "0" vagy "1" lehet. A bit az angol "Binary digit" azaz "bináris számjegy" szvak rövidítése. A gépben minden szám binárisan van ábrázolva, mely számok bitekből állnak )0-ákból vagy 1-esekből). A legtöbb házi számítógépen egy memóriarekesz vagy egy regiszter 8 bitet tud tárolni. Így a legnagyobb szám ami az akkumulátorban elfér:

11111111

Ami megfelel 255-nek decimális számrendszerben. 8 bitet hívunk egy bájtnak. Észre foguk venni a későbbiekben, hogy az akkumulátor, a magas és alacsony és a programszámláló regiszterek mind egy bájt (8 bit) hosszúak.

Assemblerek
Emlékezzünk arra, hogy a számítógép csak számokkal képes dolgozni, és nézzük az előbbi kis programot:

LD A,123

Maga az utasítás "LD A" nem szám! Hogyan tud a gép mégis dolgozni vele? Itt jön az assembler (fordító) program szerepe. Ez az a program amely az "LD A" szövegből számot, az úgynevezett utasításkódot csinálja és tárolja a memóriában. (Az assembler program helyett ezt most a szimulátor végzi el.) Az utasításkód egy 8 bites szám a gépben. Ezt a leírásokban általában hexadecimális számként írjuk le, mert így rövidebb és könnyebben kezelhető. A Z80-as processzorban az LD A utasításkódja 62 (3E HEX-ban).
Összefoglalva: az assembler program funkciója, hogy könnyebb legyen gépi kódú programokat írni. Az utasítások, amelyekből összeáll egy gépi kódú program, számokból állnak, amelyeket utasításkódoknak nevezünk. Lehetséges lenne úgy programot írni, hogy egyszerűen utasításkódokat írnánk egymás után. A legtöbb ember számára azonban egyszerűbb ezeket a mnemonikoknak a használata. Az assembler fordítja ezeket a mnemonikokat számokká vagyis utasításkódokká és elhelyezi a memóriában.

A programszámláló
Figyeljük meg, hogy az ábrán a PC regiszter értéke a program futása után 0-ról 2-re változott. Miért van ez így? A válasz egyszerű! Nézzük megint a programunkat:

LD A,123

Ahogy azt már láttuk, az LD A egy egybájtos számként van a memóriában tárolva. A 123 operandus

01111011

Bináris számmá alakul át, ami ugyancsak egy bájt (8 bit). Azt mondtuk a szimulátornak, hogy a 0-s címen kezdjen, ezért az utasításkód a 0. bájton lesz tárolva, míg a 123 az 1. bájton.
A programszámláló automatikusan 0-ra áll a program végrehajtása előtt. Végrehajtáskor itt találja az "LD A"-t, aminek szüksége van arra a számra, amit be kell írni az akkumulátorba. Ez lesz a következő bájt. Ezért a programszámláló a 2. bájtra mutat, mert a működés során az első két bájt már lefutott, a következő utasítást a 2. bájtról kell(ene) olvasni. A programszámláló a következő végrehajtandó utasításra mutat. Lényeges megjegyezni, hogy a programszámláló memória helyekkel(bájtokkal) és nem sorszámokkal dolgozik. Néhány utasítás, például az akkumulátorba töltés két bájtot vesz igénybe. Mások esetleg csak egyet! A programszámláló tudja, hogy egy utasításnak hány bájtra van szükséges így mindig automatikusan a következő utasításra mutat.

3. További gyakorlatok a szimulátorral

Továbbiak az "LD"-ről

Valószínűleg elég jól tudja mindenki, aki idáig eljutott, mit is csinál, mire való a programunk. Próbáljuk meg kitalálni, mit jelent a következő két sor!

LD H,123
LD L,123

Hogy lássuk, jól tippeltünk-e, adjuk meg a gépnek a fenti sorokat és futtassuk le. Ne feledjük, hogy minden új program beírása előtt az "X" megnyomásával törölnünk kell az előzőleg beírt programunkat! Most próbájuk ki a következőt:

LD H,7
LD A,H

Miután ezt beütöttük a következőt kell látnunk a képernyőn:

0 LD H,7
2 LD A,H

Lépdeljünk végig a programon (0-s sebességgel futtassuk a programot). Ahhoz, hogy az első sort futtassuk, le kell ütnünk valamilyen billentyűt (de nem az ENTER-t). Ismételt billentyűnyomásra a következő sor hajtódik végre. A 0-s és 1-es bájtokon lévő utasítás a 7-es számot a H regiszterbe teszi. A 2-es és 3-as bájtok az A regiszterbe teszik a H regiszter tartalmát.
Írjuk be és futtassuk a következő programot. Próbáljuk meg saját magunk kitalálni mi is történik!

LD L,6
LD H,9
LD A,L
LD L,H
LD H,A

Ha sikerült követni a programot, akkor már elég sokat tudunk az LD utasításról (egyenlőre), Van az LD utasítás használatának egy másik módja is, ezt indirekt címzésnek hívjuk és ezzel később foglalkozunk.
Mielőtt továbbmennénk, próbáljuk ki a következőt. Gépeljük be:

LD A

És üssük le az ENTER-t. Ennek hatására a következő üzenet jelenik meg: "ROSSZ". Ez azért van, mert az LD A utasítás önmagában nem értelmezhető. Az LD A (vagy LD H, stb.) megkívánja, hogy álljon utána még valami (az operandus). Innen tudja, hogy mit kell töltenie az A-ba. Ahogy láttuk, az operandus szintén lehet H vagy L azaz egy másik regiszter. Ebben az esetben ezek tartalma töltődik az akkumulátorba. Minden esetben, amikor hiba történt begépeléskor ez a "ROSSZ" felirat megjelenik, valamilyen hiba történt begépeléskor. Ilyenkor egyszerűen újra be kell gépelni a sort (helyesen), és leütni az ENTER-t. Ez a hibaellenőrzés a szimulátor szolgáltatása!

Néhány új utasítás

HALT

Ez nagyon egyszerű. Leállítja a program futását, nem engedi, hogy a további programsorok végrehajtódjanak (lehet, hogy a memóriában ezután lévő számok nem is programként értelmezhetők, hanem adatként!). ha beírjuk a következő programot:

LD A,3
HALT
LD H,5

Az LD H,5 nem fog lefutni, előtte megállítottuk a program futását.

ADD
SUB

Ezek a parancsok az akkumulátor regiszterrel vannak kapcsolatban. Aritmetikai műveleteknél ez a leggyakrabban használt regiszter. Az akkumulátort úgy képzeljük el, mint a processzor "munkapadját". Az

ADD 5

Azt jelenti, hogy az 5-öt hozzáadja az akkumulátor jelenlegi tartalmához, és az eredményt az akkumukátorbanhagyja. A

SUB 2

Utasítás kivon 2-t az akkumulátor aktuális tartalmából és az eredményt az akkumulátorban tárolja. Próbáljuk ki a következőt:

LD H,7
LD A,H
ADD 3
SUB 6
LD L,A

Ha lefuttatjuk a programot, a 4-es szám lesz az L regiszterben. (7+3-6)

JP

Ez a mnemonik a JUMP (ugrás) szóból keletkezett, és megfelel a BASIC "GOTO" utasításnak. Egy számnak lel utána állnia. A szám a memóriacímet jelöli, ahova ugrani szeretnénk. Próbáljuk ki a következő programot:

LD A,1
ADD 5
JP 2

Kilistázva a program így néz ki:

0 LD A,1
2 ADD 5
4 JP 2

Futtatáskor a "JP 2" utasítás a processzort a 2-es bájtra küldi, ahol az "ADD 5" utasítást tárolja. Ez a program sorozatosan 5-öket ad az akkumulátorhoz. Ha néhányszor futtatjuk a programot, akkor ez világos lesz.

A programok időbeni késleltetéssel való futtatása
Egészen idáig a programjainkat soronként futtattuk, billentyűnyomásonként (0-s sebesség). Ezt úgy hívjuk, hogy léptetve futtatjuk a programot, ami nem a processzor normális üzemmódja, az utasítások rendkívül gyorsan, emberi beavatkozás nélkül hajtódnak végre. Így futtatva a programokat, azonban nem lenne időnk futatás közben tanulmányozni programunk működését. A szimulátor ezért lassítva is tudja a programokat végrehajtani, mégpedig megadhatjuk, mennyi időt várjon a program utasításai között. 1 és 255 közötti számot adhatunk meg. Nulla megadása a már ismert lépésenkénti módban fog futni a program.

INC
DEC

Ezek az utasítások 1-el növelik (INC), vagy csökkentik (DEC) az A, H vagy L regiszter tartalmát. Próbáljuk ki a következő programmal:

LD A,7
LD H,10
LD L,15
ADD 5
SUB 2
INC A
INC H
INC L
DEC A
DEC H
DEC l
HALT

A program végigkövetése után világossá válnak ezek az utasítások is. A lényeg ezekkel az utasításokkal kapcsolatban, hogy az ADD és a SUB mindig az akkumulátorral dolgozik, az INC és a DEC bármelyik regiszterrel az A, H, L közül.

4. Logikai utasítások: AND, OR, XOR

Ezek az utasítások két regisztert hasonlítanak össze bitről-bitre. Az összehasonlított regiszterek lehetnek:
A-t H-val vagy
A-t L-el
A számok bitről bitre hasonlítódnak össze és az eredmény az A regiszterben keletkezik. Az összehasonlítás általános szabályai a kövtkezők:

AND

Ha mindkét bit 1-es, akkor az A-ba eredményként 1 kerül. Két nulla, vagy 0 és egy 1-es eredménye 0 lesz. Ezt ÉS műveletnek hívják, ugyanis az eredmény akkor 1, ha az első és a második bit egyes.

Tehát ha az akkumulátorban 101 van
és az L-ben 100 van,
akkor a művelet eredménye: 100

 

OR

Ha bármelyik bit 1-es, akkor az eredmény 1, egyébként 0. Ezt a műveletet VAGY műveletnek nevezik, ugyanis az eredmény akkor 1, ha az első vagy a második bit egyes.

Tehát ha az akkumulátorban 101 van
és az L-ben 100 van,
akkor a művelet eredménye: 101

 

XOR

Ha valamelyik bit (de NEM mindkettő) 1-es, akkor az eredmény 1, egyébként 0. Ezt a műveletet "kizáró" VAGY-nak nevezik, mert hasonló a vagy művelethez, de kizárja azt a lehetőséget, amikor mindkét bit 1.

Tehát ha az akkumulátorban 101 van
és az L-ben 100 van,
akkor a művelet eredménye: 001

Ahhoz, hogy ezeket a szimulátoron lássuk, próbáljuk ki ezeket a programokat:

LD A,5
LD H,4
AND H
LD A,5
LD L,4
OR L
LD A,5
LD H,5
XOR H

Ezután próbáljuk ki ezeket az utasításokat 128-nál nagyobb számokkal és figyeljük meg, hogyan működnek 8 bittel.

5. Jelzőbiket. Új utasítások: CP, RRA,RLA,SRA, SLA

Jelzőbitek (FLAG-ek)
A jelzőbitek a processzor által végzett logikai vagy aritmetikai műveletek eredményéről jegyeznek fel információkat. 6 jelzőbit van a Z80-ban. A szimulátor két jelzőbittel működik. Az egyik a CARRY (áttvitel), a másik a ZÉRO. Mindkét jelzőbitnek két állapota van, melyeket különbözőképpen értelmezünk:
TRUE / ON - FALSE / OFF
SET / 1 - CLEAR / 0
Természetesen a gépben a jelzőbitek 0-s vagy 1-es értéket vehetnek fel.

A ZÉRO jelzőbit
Ahhoz, hogy lássuk, hogyan működik, futtassuk a következő programot:

LD A,30
SUB 30

Nézzük meg a ZÉRO flag-et! A "SUB 30" utasítás az akkumulátor tartalmából kivon 30-at, s így nulla marad benne. Ekkor a NULLA jelzőbit 1-esre áll. Emlékezzünk arra, hogy az utasítás végrehajtása után állítódik a jelzőbit. Ha a ZERO flag 1-es, akkor az eredmény 0 volt, ha a jelzőbit 0 akkor az eredmény nem nulla volt.
A következő utasítások átírják a ZERO jelzőbitet:
ADD, AND, SUB, OR, INC, XOR, DEC, CP

A CARRY flag
Futtassuk a következő programot:

LD A,255
ADD 1
ADD 1
SUB 1
SUB 1
HALT

Figyeljük meg alaposan a Z és a C jelzőbiteket és az A regisztert miközben léptetjük a programot. A szimulátor CARRY (átvitel) jelzőbitje beállítódik 1-esra, ha egy összeadás átvitelt er3edményez, vagy ha egy kivonás eredménye negatív lenne (példák: 255+1 és 5-7). Más esetben a CARRY törlődik (0 értéket vesz fel). Ebben a szimulátorban a következő utasítások állítják az átviteli jelzőbitet:
ADD, SUB, INC, DEC, AND, OR, XOR, CP, RRA, RLA, SRA, SLA
A jelzők elengedhetetlenül szükségesek a feltételes utasításokhoz. Ezeket később érintjük.

A CP utasítás

Ez az utasítás egy kivonást végez el: az akkumulátor tartalmából kivonja a megadott számot, és beállítja a ZERO és a CARRY jelzőbiteket az eredménynek megfelelően. A kivonás eredménye sehol nem jelenik meg, csak a jelzőbitek állítódnak. Futtassuk a következő programot:

LD A,40
CP 40
CP 10
CP 60
HALT
40-et tesz A-ba
kivonás: 40-40=0, állítja a ZERO flaget
kivonás: 40-10=30, Z és C flag-ek nullák
kivonás: 40-60=20, ZERO=0; CARRY=1

Egy következő program:

LD A,40
CP 60
CP 10
LD H,60
CP H
HALT

Emlékezzünk a következőkre: a CP utasítás csak a flag-eket állítja, az A, H, L regiszterek tartalma változatlan marad.

RRA és RLA

Ezek az utasítások megfogatják az A regiszter tartalmát jobbra vagy balra egy bittel. A CARRY jelzőbit mint a 9. bit szerepel.

RLA
RRA

A fentiek illusztrálására próbáljuk ki a következő programokat. Különösen figyeljünk az A regiszrter és a CARRY flag változásait!

LD A,8
RRA
JP 2
LD A,0
RLA
JP 2

Eztán ezt futtassuk:

LD A,129
RRA
RLA
RRA
RRA
RLA
RLA
RLA
RLA
RLA
HALT

Kétszerezés és felezés
Az előző példában azért választottuk a 129-es számot, mert ennek bináris alakjában mindkét széléN van egy 1-es. A forgató utasításoknak van azonban egy hatásuk, ami másik számon jobban feltűnik. Lépegessünk végig az előző programon mégegyszer, de az első utasítás LD A,16 legyen az LD A,129 helyett. Figyeljük az A regiszter értékeit!

SLA és SRA

Ezek a mnemonikok a következőket jelentik: "told el az akkumulátor tartalmát egyel balra". A különbség az eltoló és a forgató utasítások között az, hogy az eltolás esetén a CARRY flag-ből nem kerül a bit tartalma vissza a jobb szélső bitbe, hanem oda mindig 0 kerül. A következő program ez érthetőbbé teszi:

LD A,129
SRA
SLA
LD A,129
SLA
SRA
HALT

6. A verem. PUSH és POP, CALL és RET

A verem (angolul: stack) a memóriának egy területe, amely számok tárolására alkalmas, de speciális módon használható. A szimulátorban ez a terület a 7-es lap 255 bájtján kezdődik. Ez a szimulátor 7-es lapjára vonatkozik. Erről még teljes részletességgel szót ejtünk a 10. fejezetben, de egyenlőre, hogy hol is van ez a verem az ne érdekeljen bennünket. Hogy lássuk miről is van szó, futtassuk a következő programot és különösen a verem (STACK) részét figyeljük a képernyőnek.

LD A,7
PUSH A
HALT

Az A regiszter tartalma le lett tárolva a memória 255. bájtjában, a verem első rekeszében. A "PUSH A" utasítás az akkumulátor tartalmát teszi a verembe. Próbáljuk ki a következő programot! (ld. ábra)

LD A,4
LD H,5
LD L,6
PUSH A
PUSH H
PUSH L
HALT

Figyeljük futás közben a vermet és láthatjuk, hogy a veremmutató (STACK POINTER) automatikusan változik. A veremmutató most a 253-ra mutat, ahol a 6-os van tárolva. A vermet tehát a következőképpen is hívják: "last in first out store" azaz "ami utoljára be az elsőnek ki tároló". Hogy miért van, az kiderül ebből a programból:

LD A,4
LD H,5
LD L,6
PUSH A
PUSH H
PUSH L
POP A
POP H
POP L
HALT

Láthatjuk, hogy amelyik számot utoljára betettük a verembe, az kerül ki onnan először. Kicsit ahhoz lehet hasonlítani, amikor egy önkiszolgáló étteremben a személyzet kiteszi a tálcákat, mert kezd elfogyni, akkor azokat a tálcákat veszik el először, amit utoljára tettek ki. Észrevehettük, hogy az az utasítás, ami a veremből kivesz egy számot, az a POP utasítás. A PUSH és a POP utasítás után mindig egy regiszter kell, hogy álljon (A, H, L)

CALL és RET

Most, hogy a verem fogalmát bevezettük, megismerkedhetünk a CALL és a RET utasításokkal. A CALL nem más, mint egy speciális ugró utasítás, ahol a verembe letárolódik az a cím, ahová a szubrutin végrehajtása után vissza kell térni. A CALL utasítás leteszi a verembe a CALL utáni utasítás címét és elugrik egy szubrutin elejére.
A RET a programszámlálóba helyezi a verem tartalmát. Ahhoz, hogy lássuk, hogyan is működik mindez, futtassuk a következő programokat:

0 CALL 3
2 INC A
3 HALT

Ez a program elugrik a 3-as bájtra. Az "INC A" utasítás soha nem hajtódik végre. Mindamellett jegyezzük meg, hogy a 2-es cím bekerül a verembe. Nézzük a következőt:

0 CALL 4
2 INC A
3 HALT
4 RET

A "CALL 4" a "RET"-re ugrik és 2-t tesz a verembe. A RET kiveszi az utolsó verembe tett értéket (2) és beteszi a programszámlálóba, ami azt jelenti, hogy a 2-es címen fog folytatódni a végrehajtás.
Ez a két utasítás lehetővé teszi, hogy kiugorjunk a programból egy szubrutinba és onnan a helyes következő utasításra térjünk vissza. Olyan ez mint a Basic-ben a GOSUB. Íme még egy példaprogram, amely a RET működését szemlélteti:

0 LD A,5
2 PUSH A
3 RET
4 INC H
5 HALT

Miután a RET utasítás az utoljára a verembe tett értéket a programtárolóba teszi, ezért a program a 3-as címről az 5-ösre fog ugrani és kihagyja az "INC H" utasítást.

Figyelem!
A CALL és a RET utasítások együtt használatosak szubrutinhíváskor és a veremműveleteket a processzor automatikusan végzi el. A programozónak mindig figyelemmel kell lennie a PUSH és a POP utasítások számára és helyes használatára, mert könnyen előfordulhat, hogy szubrutin visszatérési címeink elromlanak.

A PUSH és a POP általános használata
A PUSH-t általában szubrutinhívások előtt használjuk. Itt elmenthetjük a regiszterek tartalmát a verembe. Így a szubrutin használhatja a regisztereket és az előzőleg bennük tárolt értékek nem vesznek el. A POP-ot ilyen esetben a szubrutin hívása után használjuk az eredeti regiszterértékek visstaállítására.

7. Feltételes ugrások, indirekt címzés

Feltételes ugrások
Ezek egész alapvetőek és a számítógép programozás lelkét adják, miután ez teszi lehetővé a program futásának meghatározását az adatoktól függően. Ebben a szimulátorban négy olyan feltétel van, amelyektől függően lehet ugrani. Ezek:

Itt láthatunk egy példát a feltételes ugrásokra. A program 35-öt elosztja 5-tel és az eredmény a H regiszterben keletkezik:

LD A,35
INC H
SUB 5
JP NZ,2
HALT

Futtassuk a programot akár többször is, hogy lássuk hogyan működik. Itt van egy másik program. Vajon mit csinál? Figyeljük az akkumulátort a program végén.

LD H,8
ADD L,6
ADD H
DEC L
JP NZ,4
HALT

A szimulátorban három utasítást használhatunk feltételes ugrásokra. Ezek a következők:
JP, CALL, RET

Ezekkel már találkoztunk a feltétel nélküli formájukban, Például a "JP 2" utasítás elugrik a 2-es címre. Ennek a feltételes változata:

JP f,2

Ahol "f" a jelzőbitek állapotát mutatja és a következő lehet (ezeket már ismerjük):
Z, NZ, C, NC
Így a "JP NZ,8" utasítás elugrik a 8-as bájtra, ha a ZERO jelzőbit 0. A "CALL C,26" utasítás meghívja a 26. bájton kezdődő szubrutint, ha a CARRY jelzőbitben 1 van. Ezek után érthető az ASSEMBLER képernyőn látható következő néhány sor:
CALL f,n
JP f,n
RET f
A fenti utasítások az "f" nélkül is használhatók.

Indirekt címzés
Futtassuk a következő kis programot:

LD H,30
LD L,40
LD (L),123
LD (H),200
LD A,(L)
HALT

Futtatás közben figyeljük a regiszterek tartalmát és a kijelző memória részét. Ha H-t vagy L-et zárójelbe tesszük, akkor a regiszterben lévő számnak megfelelő memóriarekeszre hivatkozunk. Ezt szem előtt tartva futtassuk még egyszer a programot.

LD H,30
LD L,40
LD (L),123
LD (H),200
LD A,(L)
HALT
Tárolja a 30-at H-ban
Tárolja a 40-et az L-ben
Tárolja a 123-at a 40-es memóriacímen
Tárolja a 200-at a 30-as memóriacímen
Tárolja az A-ban a 40-es memóriarekesz tartalmát

8. A két hátralévő parancs: OUT és DATA. Az assembler képernyő.

OUT

Ez az utasítás az akkumulátorban lévő számnak megfelelő ASCII karaktert kiírja a képernyőre. Az utasításnak nem láthatóm eredménye, ha az érték 32 alatt vagy 159 felett van, mert ezek nem megjeleníthető karakterek. A következő program demonstrálja az OUT utasítást.

LD A,32
OUT
INC A
JP 2

A program elkezd írni a bal felső sarokban és teleírja az egész első sort. Ha az első megtelt, akkor a másodikban folytatja. Mit csinál, ha a legalsó sor is megtelt? A képernyőnek van egy-két speciális tulajdonsága, ami erre választ ad és a következő fejezetben ejtünk szót ezekről.

DATA

Elöljáróban megjegyezzük, hogy ez nem egy Z80-as utasítás, hanem csak az assembler használja. Az utasítás letesz egy számot a memóriába a következő szabad helyre. Példaképp próbáljuk ki a következőt:

DATA 1
DATA 23
HALT

Amikor lefuttatjuk a programot, az 1-es számot láthatjuk a memória 0-s bájtján, a 23-at az 1. bájtban. Próbáljuk ki a következőt:

DATA 62
DATA 32
DATA 211
DATA 60
DATA 195
DATA 2

Az eredmény ismerős kell hogy legyen. Ugyanazt kell tennie ennek a programnak, mint az OUT utasítást demonstráló programnak Miért?
Ahhoz, hogy megértsük mi is történt, vissza kell mennünk az utasításkódokhoz. Emlékezzünk arra, hogy a számítógép csak számokkal dolgozik és az assembler alakítja az utasításokat számokká. Ha újra beadnánk az OUT utasítás demonstráló programot, ugyanazokat a számokat látnánk, mint a DATA utasítást bemutató program esetében.

mnemonik
utasításkód
LD A
62
OUT
211
DEC
61

Ez akkor válik világossá, ha néhányszor lefuttatjuk mindkét programot. Megírhatjuk saját kis programunkat a DATA utasítások segítségével. Láttuk az előbbiekben, hogyan használjuk a DATA utasítást, de azt nem, hogy mire. Szám-táblák felállítására használhatjuk. Próbáljuk ki a következő programot, ami tartalmaz indirekt címzést, és jó pár utasítást.

LD H,13
LD L,9
LD A,(H)
OUT
INC H
DEC L
XOR A
CP L
JP NZ,4
HALT
DATA 01H
DATA 02H
DATA 18H
DATA 53H
DATA 63H
DATA 72H
DATA 111
DATA 108
DATA 108

Ne feledjük, hogy a szimulátor felépítése miatt maximum 255 utasítás és DATA bájt írható be.

Hexadecimális számok használata
Akkor írhatunk programunkba hexadecimális (16-os számrendszerbeli) számokat, amikor csak akarunk. Figyeljük meg, hogy az előző programban 13-as bájttól a 21-ig lévő DATA utasításokban decimális és hexadecimális számokat is használtunk. Hexadecimális számokat úgy vihetünk be, hogy a szám után egyszerűen egy H betűt írunk, ezzel jelezzük a szimulátornak, hogy hexadecimális számot adtunk meg.
Így a
23H megfelel decimális 35-nek, mivel
(2*13)+(3*1) = 32+3 = 35
Ha akarjuk, a képernyő a képernyő hexadecimális üzemmódú is lehet, ha a menüben a számrendszer opciót (H billentyű) "hex"-re állítjuk.

Az Assembler képernyő
Az alábbiak
F = Z, ZC, C, NC
S = AHLP (H) (L) n
P = AHL
Jelentése, ha a mnemonikokkal kapcsolatban használjuk őket biztosan érthető. Az esetleges kétségek eloszlatására álljon itt néhány példa:

9. Vezérlő kódok

Amikor egy numerikus kódot küldünk a képernyőre (OUT), a megfelelő karakter jelenik meg. Pl. a 65-ös hatása az "A" betű. Nem minden kódnak van azonban a képernyőn látható eredménye. Ezeket általában vezérlő kódoknak hívjuk, és bizonyos hasznos utasítások kiadására használjuk őket - mint például a képernyő törlése vagy a következő sorba ugrás.
Hogy a vezérlő kódok használatát gyakorolhassuk, ebben a szimulátorban van öt speciális kód (0-4). Ezek mindegyike úgy manipulálja a képernyőt, hogy látható legyen, mi történik. Látni fogjuk, hogy ez egy hatékony eszköz ha grafikus képernyőt akarunk összeállítani.

0. vezérlőkód: Képernyő törlés
Az alábbi program példázza ennek használatát.

LD A,48
LD L,13
OUT
INC A
DEC L
JP NZ,4
LD A,0
JP 0

1. vezérlőkód: egysoros üzemmód
Általában a kiírás 5 sornyi területre történik, de ezt az 1-es vezérlőkód használatával meg lehet változtatni. A következő program ennek az üzemmódnak a használatát mutatja be, valamint azt, hogy mi történik akkor, ha betelik a sor.

LD A,1
OUT
LD H,3
LD L,26
LD A,65
OUT
INC A
DEC L
JP NZ,9
DEC H
JP NZ,5
HALT

4. vezérlőkód
Az 1-essel ellentétes értelmű kód. Változtassuk meg az előző programot úgy, hogy mondjuk húsz karakter kiírása után küldjön ki egy 1-es kódot, és figyeljük meg, mi történik, ha újabb tíz karaktert írunk ki!

2-es és 3-as vezérlő kódok: kiírási pozíció meghatározása
A 2-es és 3-as kódok után egy-egy byte-ot még ki kell küldeni a képernyőre mielőtt bármit tennénk. A 2-es lód olyan, mint a BASIC PRINT AT parancs, azaz lehetővé teszi, hogy a kiíratás a képernyő tetszőleges pontjára történjen. A második kiküldött byte határozza meg, hova íródik majd a következő karakter. Ha a kiírt byte értéke 0 és 24 között van, a karakter a legfelső sorba kerül, 0 esetén a baloldalra, 24 esetén a jobbzélre. Hasonlóan:

Mindig a növekvő értéknek megfelelően balról jobbra. Ezt a következő program szemlélteti:

LD H,15
LD L,5
LD A,2
OUT
LD A,H
OUT
ADD 25
LD H,A
LD A,65
OUT
DEC L
JP NZ,4
HALT

Próbaképpen változtassuk a H értékét a program első sorában.
Figyeljük meg, mi történik, ha a 2-es kód után kiküldött szám nagyobb, mint 124 (érvénytelen képernyőpozíció). Ha a képernyő az egysoros üzemmódban van, akkor csak 0-24 az érvényes intervallum. Az alábbi programban a H értékét változtatva megfigyelhetjük ezeket az eseteket is.

LD H,12
LD A,1
OUT
LD A,2
OUT
LD A,H
OUT
LD A,90
OUT
HALT

A 3-as vezérlő kód épp a 2-es ellenkezőjét csinálja. Az A regiszterben visszaadja a képernyő adott pontján lévő karakter ASCII kódját. A képernyő pozíciót az előbbi módon kell megadni. Ez a képesség igen hasznos lehet egy játékprogramban, amikor is ellenőrizhetjük, hogy pl. egy rakéta eltalálta-e a célt.

10. A P regiszter

Ha hosszú programot akarunk írni,, a 256 byte memóriát kevésnek fogjuk találni. Éppen ezért a szimulátor 8-szor 256 byte-al van ellátva. Mivel a programszámláló (PC) csak 255-ig nőhet, mi történik, ha a program tovább folytatódik?
E célra egy külön P nevű "lapregisztert" hoztak létre, ami valójában a PC regiszternek a kibővítése, és amely a PC regiszternek, megmondja, melyik 256 byte-ot kell értelmeznie. Ezt leginkább a következő programmal illusztrálhatjuk a legjobban: írjuk be először a 0-s címre a következő "parancsot":

JP 254

Majd lépjünk ki az assembler-ből (ENTER leütésével), és lépjünk ismét be az A leütésével. Amikor az a kezdőcímet kérdezi, írjuk be 254-et, azután gépeljük be a következőket:

INC A
INC A
INC A
INC A
INC A
HALT

Észrevehetjük, hogy a képernyő alján a lapszám (page number) 0-ról 1-re vált abban a pillanatban, amikor a begépelt INC A utasítás címe 255-ről 0-ra vált. A lapszám mutatja, melyik 256 byte-os blokkon belül vagyunk. Indítsuk el a programot és figyeljük a PC és a P regisztert.
Ezt a "lapozásos" technikát maga az Enterprise is használja, mert a központi egységnek ott is sokkal nagyobb memóriát kell címeznie, mint amennyit fizikailag tud. Ebben az esetben a P (lap-)regiszter nem a processzornak (CPU), hanem a CPU-t és a memóriát összekötő hardware-ben található.

Mit tegyünk, ha a programban ugrani akarunk (jump) vagy egy külön programrészletet akarunk meghívni (call). Hová ugrik a program, ha pl. azt írjuk be, hogy JP 59? A P regiszter programozásával bármelyik programrészletre ráugorhatunk. Írjuk be a következőket:

LD P,2
JP 5
INC A
INC A
HALT

Lépjünk vissza az assemblerbe, és kezdőcímnek írjuk be ismét: P2,5. Ennek hatására az assembler a 2. lapon fogja a programot elindítani. Írjuk be:

DEC A
HALT

És futtassuk le a őrogramot. Azt tapasztaljuk, hogy az INC A utasítások egyszerűen kimaradnak, a program egyből DEC A-ra ugrott. Ezzel a módszerrel tehát (a P regisztert beállítva) a nyolc blokk bármelyikébe (0-7) ugorgatunk. Ne feledjük, hogy ha egy CALL utasítás előtt beállítjuk a P regisztert, akkor a RET utasítás végrehajtása előtt vissza kell állítani az eredeti értékre, máskülönben a program rossz helyen folytatja működését (azaz nem működik). A P regisztert beállíthatjuk valamely indirekt címzésű művelet előtt is, s így bármelyik blokk adatait elérhetjük.

11. Gyors futtatás, töltés és mentés, listázás

Gyors futtatás
Írjuk be a következő programot:

LD A,79
OUT
JP 2

Ha ezt a programot késleltetéssel futtatjuk, az természetesen lassú lesz. Ha azt akarjuk, a program sokkal gyorsabban is futhat. Ehhez az R módot kell választanunk, amikor a késleltetést kérdezi a gép. Ezután a kijelző terület csak a képernyő közepén lesz, a program sokkal gyorsabban fog futni. Ez úgy lehetséges, hogy a szimulátor programnak nem kell frissítenie a képernyőn a regiszterek értékét. Továbbra is az ENTER lenyomásával léphetünk ki a programból. Bár az R módban a programok igen gyorsan futnak, ez még mindig 200-szor lassabb, mint a valódi gépi kódú program futása a szimulátor nélkül.

Mentés és töltés (SAVE és LOAD)
A menü lapon találhatunk SAVE és LOAD opciót is. Az S vagy L betűt lenyomva a gép megkérdezi a program nevét (max. 15 karakter, lemezes rendszerben 8 karakter hosszú). Kazettás rendszerben csak ENTER-t ütve név nélkül elmenti a programot vagy betölti a következőt. A betöltött programokat tovább írhatjuk hozzájuk fűzhetünk további sorokat.

Listázás
Az L vagy P lenyomásával programunkat bármikor kilistázhatjuk a képernyőre, vagy kinyomtathatjuk a nyomtatóra. A menü laphoz a visszatérés ENTER leütésével történhet.

12. A Z80-as mikroprocesszor

A Z80-as mikroprocesszor (a logikus lépés a szimulátor után) két csoport regisztert tartalmaz, melyek neve A, F, B, C, D, E, L, H, ahol az A az akkumulátor, F pedig a flag regiszter. A programszámláló (program counter) és a stack mutató (stack pointer) 16 bites regiszterek, a memóriahelyekre pedig B és C, D és E vagy L és H regiszter-párokból képzett 16 bites mutatókkal címezhetünk. Vannak még index regiszterek is (IX és IY), melyek egy offset (eltolás) byte-ot is használva mutatnak egy-egy memóriahelyre. Az ugrások végrehajtása is történhet relatív címek (eltolás) alapján, rotáló (ciklikus eltolás) és bit manipuláció utasítás.
Sok magasabb szintű könyv is létezik, melyekből a részleteket alaposan megismerhetjük

Függelék

A. Decimális számok (10-es számrendszer)

A számokat a mindennapi életben decimális számrendszerben írjuk. Példaképp nézzük az 5432-es számot.

 
1010*10
10*10
10*1
 
helyértékek:
1000
100
10
1
 
5
4
3
2

Tudjuk hogy:

Ezért úgy olvassuk ki a számot, hogy ötezernégyszázharminckettő. Az 1000, 100, 10 és az 1 helyiértékű a 10-es számon alapszanak. A 10-es számrendszerben 10 különböző jelet használunk a számok írásánál:
0 1 2 3 4 5 6 7 8 9

B. Bináris számok (kettes számrendszer)

Két alapvető dolog van, mait tudni kell a bináris számokról Ezek a következők:

2*2*2*2*2
2*2*2*2
2*2*2
2*2
2*1
 
32
16
8
4
2
1

Ahhoz, hogy kiszámoljuk egy bináris szám decimális értékét, a szám fölé kell tenni a helyértékeket. Például nézzük a következő bináris számot. 10110. Írjuk fölé a helyértékeket:

16
8
4
2
1
1
0
1
1
0

Ennek a számnak az értéke tehát a következő:

1 * 16 = 16
8 * 0 = 0
1 * 4 = 4
1 * 2 = 2
0 * 1 = 0
összesen: 22

Minden szám felírható 0-ák és 1-esek segítségével bináris alakban. Itt láthatunk néhány példát:

1
1
1 0
2
1 1
3
1 0 0
4
1 0 1
5

C. Hexadecimális számok (16-os számrendszer)

A helyértékek a 16-os számrendszeren alapulnak.

16*16*16*16
16*16*16
16*16
16
 
65536
4096
256
16
1

16 jelet használunk a számok felírásához. Eddig csak tíz jelet ismertünk (0, 1 ... 9) ezért be kell újakat vezetnünk. Ezek a következő betűk lesznek:
A, B, C, D, E, F.

decimális
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
hexa
0
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F

Ahhoz, hogy kiszámoljuk egy hexa (értsd: hexadecimális) szám decimális értékét, ahhoz a helyértékeket fölé kell írni. Nézzük a következő számot: 3AB. Ezt általában 3ABH-nak szokás leírni, a szám végén a "H" jelöli, hogy hexadecimális számról van szó. Írjuk fölé a helyértékeket:

256
16
1
3
A
B

A szám értéke így jön ki:

3 * 256 = 768
10 * 16 = 160
1 * 11 = 11
összesen: 939

Miért használunk 16-os számrendszert?
A központi egység 8 bites regisztereket használ. Egy bit alatt egy 0-át vagy 1-et értünk 2-es számrendszerben. Így a regiszterekben 00000000 és 11111111 (0 és 255) közötti számokat ábrázolhatunk.
A számok kényelmesebb írása mellett megállapodás szerint gyakran hexadecimális számrendszert használunk. Négy bináris jegy 0 és 15 között ábrázolhat számokat. A következő táblázat érthetőbbé teszi mindezt:

Bináris
Decimális
HEX
 
Bináris
Decimális
HEX
0000
0
0
 
1000
8
8
0001
1
1
 
1001
9
9
0010
2
2
 
1010
10
A
0011
3
3
 
1011
11
B
0100
4
4
 
1100
12
C
0101
5
5
 
1101
13
D
0110
6
6
 
1110
14
E
0111
7
7
 
1111
15
F

D. A szimulátor használatának összefoglalása

A szimulátor használata:
Amikor a menü képernyő megjelenik nyomjuk le egy A-t a program írásához. A kezdőcimnek 0-át javasolt adni (de nem kötelező), utána ENTER. Most az assembler-ben vagyunk. Minden utasításban szóközt kell tennünk az utasítás kód és az operandus közé. Számok beírhatók decimálisan vagy hex-ben a H betűvel a szám végén. A törlő billentyű normális módon működik. Miután sikeresen begépeltük a programot, nyomjuk le egy sima ENTER-t. Ennek hatására kilépünk az assembler-ből. És a főmenühöz kerülünk. Itt nyolc lehetőség van:

Futtatás előtt egy késleltetési számot kell megadnunk. Ez mutatja, mennyi idő teljen el két utasítás végrehajtása közt. A program bármikor megállítható ENTER billentyűvel.

Elérhető utasítások:

ADD Összeadés
AND ÉS logikai művelet
CALL Szubrutinvívás
CP Összehasonlítás
DATA Adat elhelyezése memóriában
DEC Dekrementálás
HALT Program leállítás
INC Inkrementálás
JP Ugrás
LD Töltés
OR VAGY logikai művelet
OUT Karakter kiírás
POP Veremből ki
PUSH Verembe be
RET Visszatérés szubrutinból
RLA Balra forgatás (bitenként)
RRA Jobbra forgatás (bitenként)
SLA Balra eltolás (bitenként)
SRA Jobbra eltolás (bitenként)
SUB Kivonás
XOR Kizáró VAGY logikai művelet