str.38

Podmíněné absolutní skoky
Výzvy podprogramů a povely k návratu
----------------------------------------------------------------|
|Mnemonic   | Působení       | Flagy | Hexkód | Analog BASIC    |
|---------------------------------------------------------------|
| Absolutní skoky podmíněné                                     |
|---------------------------------------------------------------|
| JP Z,nm   | if Z=1 PC=nm   | ----- | CA,m,n | IF Z=1 GOTO nm  |
| JP NZ,nm  | if Z=0 PC=nm   | ----- | C2,m,n | IF Z=0 GOTO nm  |
| JP C,nm   | if C=1 PC=nm   | ----- | DA,m,n | IF C=1 GOTO nm  |
| JP NC,nm  | if C=0 PC=nm   | ----- | D2,m,n | IF C=0 GOTO nm  |
| JP M,nm   | if S=1 PC=nm   | ----- | FA,m,n | IF S=1 GOTO nm  |
| JP P,nm   | if S=0 PC=nm   | ----- | F2,m,n | IF S=0 GOTO nm  |
| JP PE,nm  | if P=1 PC=nm   | ----- | EA,m,n | IF P=1 GOTO nm  |
| JP PO,nm  | if P=0 PC=nm   | ----- | E2,m,n | IF P=0 GOTO nm  |
|---------------------------------------------------------------|
| Výzvy podprogramů podmíněné                                   |
|---------------------------------------------------------------|
| CALL Z,nm | if Z=1 CALL nm | ----- | CC,m,n | IF Z=1 GOSUB nm |
| CALL NZ,nm| if Z=0 CALL nm | ----- | C4,m,n | IF Z=0 GOSUB nm |
| CALL C,nm | if C=1 CAll nm | ----- | DC,m,n | IF C=1 GOSUB nm |
| CALL NC,nm| if C=0 CALL nm | ----- | D4,m,n | IF C=0 GOSUB nm |
| CALL M,nm | if S=1 CALL nm | ----- | FC,m,n | IF S=1 GOSUB nm |
| CALL P,nm | if S=0 CALL nm | ----- | F4,m,n | IF S=0 GOSUB nm |
| CALL PE,nm| if P=1 CALL nm | ----- | EC,m,n | IF P=1 GOSUB nm |
| CALL PO,nm| if P=0 CALL nm | ----- | E4,m,n | IF P=0 GOSUB nm |
|---------------------------------------------------------------|
| Povely k návratu podmíněné                                    |
|---------------------------------------------------------------|
| RET Z     | if Z-1 RET     | ----- | C8     | IF Z=1 RETURN   |
| RET NZ    | if Z=0 RET     | ----- | C0     | IF Z=0 RETURN   |
| RET C     | if C=1 RET     | ----- | D8     | IF C=1 RETURN   |
| RET NC    | if C=0 RET     | ----- | D0     | IF C=0 RETURN   |
| RET M     | if S=1 RET     | ----- | F8     | IF S=1 RETURN   |
| RET P     | if S=0 RET     | ----- | F0     | IF S=0 RETURN   |
| RET PE    | if P=1 RET     | ----- | E8     | IF P=1 RETURN   |
| RET PO    | if P=0 RET     | ----- | E0     | IF P=0 RETURN   |
-----------------------------------------------------------------
     Podmíněné skokové příkazy mají stejnou funkci jako if v
BASICu. Nabízejí jedinou možnost řešit ve strojovém kódu
rozhodování.
     Na těchto podmíněných skokových příkazech se vždy testuje
stav jednoho CPU Flagu, a podle výsledku testu je skok proveden,
nebo se neděje nic. Podívejme se na povel ,,JP Z,nm'' (Jump if
Z set, česky skoč když Z je nastaveno). Skok je proveden jen
když Z-Flag je nastaven na 1. Toto se musí napřed provést
příslušným povelem, např. porovnávacím příkazem jako "CP 5" 
(Compare A with 5, česky porovnej A s 5). Když je při porovnání
A=5, pak bude Z=1, jinak je Z=0.

Příklad:
adresa   kód       povel          Analog BASIC

8000:    06 11     LD B,11        8000:B=11
8002:    FE 05     CP 05          8002:IF A=5 GOTO 8009
8004:    CA 09 80  JP Z,8009
8007:    06 00     LD B,00        8007:B=00
8009:    C9        RET            8009:RETURN

str.39

     Než budete startovat tento program, dejte do akumulátoru A
hodnotu např. A=12. Když teď (po PC=8000) startujete program,
dopadne porovnání A s 5 negativně a nebude proveden žádný skok,
takže na konci bude v B reg. hodnota 00. Naproti tomu když znovu
budete startovat program s A=5, pak najdete v B reg. hodnotu 11,
protože porovnání dopadlo pozitivně a povel "LD B,00" byl
přeskočen. Porovnávací povely samozřejmě nejsou jediné povely,
které ovlivňují Flaggy. To totiž dělá mnoho aritmetických povelů
např. 8bitové úbytkové příkazy (dekrementní). Povel "DEC A"
(Decrement A, česky sniž A) snižuje obsah akumulátoru o 1.
Vezmeme-li k tomu ještě povel JP NZ (Jump if Z reset, česky skoč
když Z je vynulováno), pak lze programovat počítací smyčku,
ekvivalent v BASICu pro FOR .... NEXT.
Přiklad:

adresa   kód       povel          Analog BASIC

8000:    3D        DEC A          8000:A=A-1
8001:    C2 00 80  JP NZ,8000     8001:IF A<>0 GOTO 8000
8004:    C9        RET            8004:RETURN

     Při startu programu s A=7 a <T>< >, proběhne smyčka 7krát,
jak můžete sledovat při zpracování po jednotlivých krocích.Při
prvním průběhu bude A=6, při druhém A=5......při sedmém bude
A=0 a tím se Z Flag nastaví na 1, takže teď se již neuskuteční
zpětný skok a program je ukončen. Takové počítací smyčky se ve
strojovém jazyku používají hodně, přičemž se často použije
jeden registr jako počítadlo. Samozřejmě předchází část programu
před tímto sledem povelů, která se uzavře do této smyčky, přičemž
se skáče o více než 3 byty od příkazu JP NZ zpět. Má se totiž
opakovat určitá část programu a ne nic, jako v našem příkl.

Relativní skoky nepodmíněné a podmíněné
-----------------------------------------------------------------
| Mnemonic  | Působení       | Flagy | Hexkód | Analog BASIC    |
|---------------------------------------------------------------|
| Relativní skoky nepodmíněné                                   |
|---------------------------------------------------------------|
| JR e      | PC=PC+e        | ----- | 18,e-2 | GOTO PC+e       |
|---------------------------------------------------------------|
| Relativní skoky podmíněné                                     |
|---------------------------------------------------------------|
| JR Z,e    | if Z=1 PC=PC+e | ----- | 28,e-2 | IF Z=1 GOTO PC+e|
| JR NZ,e   | if Z=0 PC=PC+e | ----- | 20,e-2 | IF Z=0 GOTO PC+e|
| JR C,e    | if C=1 PC=PC-e | ----- | 38,e-2 | IF C=1 GOTO PC+e|
| JR NC,e   | if C=0 PC=PC-e | ----- | 30,e-2 | IF C=0 GOTO PC+e|
|           |                |       |        |                 |
| DJNZ e    | B=B-1          | ----- | 10,e-2 | B=B-1           |
|           | if B<>0 PC=PC+e|       |        | IFB<>0 GOTO PC+e|
-----------------------------------------------------------------
     Povely JR (Jump relative, česky skoč relativně) se liší od
JP povelů pouze tím, že se neudává adresa přímo, kam má skok
vést, ale pouze o kolik bytů vpřed nebo nazpět se má skočit.
Začíná se počítat u adresy u které stojí JR povel jako u nulového
bodu. Odtud lze skákat až do 129 bytů dopředu nebo až o 128 bytů
dozadu. Kolik bytů se má přeskočit udává se hodnotou e, e je
8bitové číslo s předznamenáním, je-li pozitivní pak je PC
povýšeno o e (skok dopředu), je-li e negativní, pak se PC jako
komplementární dvojice snižuje o e (viz dodatek A) (skok dozadu).

str.40

Předcházející příklad povelu s JP vypadá s JR povely následovně.
Příklad:
adresy   kód       povel          Analog BASIC

8000:    18 02     JR 04          8000:GOTO 8000+4
8002:    06 99     LD B,99        8002:B=99
8004:    0E 99     LD C,99        8004:C=99
8006:    18 FE     JR 00          8006:GOTO 8006+0
8008:    C9        RET            8008:RETURN

     Nabírací povel pro B reg. se přeskočí stejně jako nahoře a
program končí rovněž v nekonečné smyčce. Vyzkoušejte si to
trasováním programu.
 Prohlédnete-li si podrobně příklad, budete se ptát proč povel
JR 04 dává kód "18 02".
Věc je jednoduchá:
Abychom při zadávání programu mohli pohodlně vycházet z adresy
u které začíná povel JR, udáte jinou hodnotu pro rozpětí skoku
než je pro CPU potřebná. CPU totiž bere stav počítadla po
přečtení JR povelu jako nulový bod, tedy adresa prvního bytu za
povelem JR.
     Programování pomocí povelů JR nabízí dvě přednosti:
Za prvé se programy zkracují, protože JR povel potřebuje jen dva
byty, za druhé lze programy v paměti volně přesouvat, když jsou
použity pouze JR povely. Jelikož u "JP 8004" stojí 8004 v
programovém kódu, vždy se tedy skáče na 8004, i když se program
má ukládat jinde. Při "JR 04" je naopak zcela lhostejné, kde
tento povel stojí, je prováděn vždy skok 4 byty dopředu.

     Bohužel neexistuje u většiny 8bitových procesorů žádný
relativní podprogramový skok, kromě toho je délka skoku omezena
na 127 bytů, takže pro delší programy je nutno použít jiných
technik, mají-li být relokatibilní (přemístitelné). Pro krátké
programy však stačí používáme-li pouze relativní skoky.
     Právě tak jako pro absolutní skokové příkazy existují též
pro podmíněné povely relativních skoků. Ovšem se dá u relativních
skoků dotazovat pouze na C- a Z- Flagy. Předcházející příklad s
povelem JP NZ vypadá s povelem JR NZ následovně:
Příklad:
adresa   kód       povel          Analog BASIC

8000:    3D        DEC A          8000:A=A-1
8001:    20 FD     JR NZ,8000-$   8001:IF A<>0 GOTO 8000
8003:    C9        RET            8003:RETURN

     Zde máte druhou a taky komfortní možnost udat v Line-
assembleru cíl skoku. Namísto pracného výpočtu rozpětí skoku,
zadáte jednoduše absolutní adresu skoku. Aby assembler věděl,
že z ní má přepočítat relativní hodnotu, připojíte k adrese -$
(poznámka pro specialisty: $ je přesně aktuální stav PC).

str.41

Povel DJNZ (Decrement and Jump if Not Zero) je zvláštností,
protože sdružuje hned obě funkce smyčky počítadla v jednu.
Registr B se sníží, a dokud obsah B nedosáhne 00 se provádí skok.

Příklad:
adresa   kód       povel          Analog BASIC 

8000:    10 FE     DJNZ 8000-$    8000:B=B-1:IF B<>0 GOTO 8000
8002:    C9        RET            8002:RETURN

     Tento příklad funguje stejně jako předcházející, pouze že
se počítá v B. Kromě toho se musí v B předesílat hodnota 6,
jestliže chceme nechat smyčku proběhnout 7 krát. Jak vidět povel
DJNZ šetří byt v programu, a co je daleko důležítější, nemění
žádný Flag jako je tomu u povelů dekrementních. Tuto vlastnost
se naučíme teprve později oceňovat, teď budiž podotknuto, že
právě u počítadlových smyček potřebujeme často informace flagů v
opakované části programu, takže nesmí být zfalšovány dekrementním
povelem.

5.2 NABÍRÁNÍ A UKLÁDÁNÍ
-----------------------
     Těmito povely se transferují data mezi registry a paměťovými
buňkami. Zčásti jsou vám nabírací povely již známy. Jinak jsou
tyto povely velice neproblematické, proto se nechceme dlouho
zdržovat u základních věcí.

8bitové nabírací a střádací povely
----------------------------------

-----------------------------------------------------------------
| Mnemonic  | Působení       | Flagy | Hexkód | Analog BASIC    |
|---------------------------------------------------------------|
| 8 bitové povely nabírací                                      |
|---------------------------------------------------------------|
| LD A,r    | A=r            | ----- | 78+reg | A=r             |
| LD A,n    | A=n            | ----- | 3E,n   | A=n             |
| LD A,(nm) | A=(nm)         | ----- | 3A,m,n | A=PEEK (nm)     |
| LD A,(BC) | A=(BC)         | ----- | 0A     | A=PEEK (BC)     |
| LD A,(DE) | A=(DE)         | ----- | 1A     | A=PEEK (DE)     |
| LD A,(HL) | A=(HL)         | ----- | 7E     | A=PEEK (HL)     |
|           |                |       |        |                 |
| LD B,r    | B=r            | ----- | 40+reg | B=r             |
| LD B,n    | B=n            | ----- | 06,n   | B=n             |
| LD B,(HL) | B=(HL)         | ----- | 46     | B=PEEK (HL)     |
|           |                |       |        |                 |
| LD C,r    | C=r            | ----- | 48+reg | C=r             |
| LD C,n    | C=n            | ----- | 0E,n   | C=n             |
| LD C,(HL) | C=(HL)         | ----- | 4E     | C=PEEK (HL)     |
|           |                |       |        |                 |
| LD D,r    | D=r            | ----- | 50+reg | D=r             |
| LD D,n    | D=n            | ----- | 16,n   | D=n             |
| LD D,(HL) | D=(HL)         | ----- | 56     | D=PEEK (HL)     |
|           |                |       |        |                 |
| LD E,r    | E=r            | ----- | 58+reg | E=r             |
| LD E,n    | E=n            | ----- | 1E,n   | E=n             |
| LD E,(HL) | E=(HL)         | ----- | 5E     | E=PEEK (HL)     |

str.42

|           |                |       |        |                 |
| LD H,r    | H=r            | ----- | 60+reg | H=r             |
| LD H,n    | H=n            | ----- | 26,n   | H=n             |
| LD H,(HL) | H=(HL)         | ----- | 66     | H=PEEK (HL)     |
|           |                |       |        |                 |
| LD L,r    | L=r            | ----- | 68+reg | L=r             |
| LD L,n    | L=n            | ----- | 2E,n   | L=n             |
| LD L,(HL) | L=(HL)         | ----- | 6E     | L=PEEK (HL)     |
|---------------------------------------------------------------|
| 8mi bitové střádací povely                                    |
|---------------------------------------------------------------|
| LD (nm),A | (nm)=A         | ----- | 32,m,n | POKE nm,A       |
| LD (BC),A | (BC)=A         | ----- | 02     | POKE BC,A       |
| LD (DE),A | (DE)=A         | ----- | ED,4F  | POKE DE,A       |
|           |                |       |        |                 |
| LD (HL),r | (HL)=r         | ----- | 70+reg | POKE HL,r       |
| LD (HL),n | (HL)=n         | ----- | 36,n   | POKE HL,n       |
-----------------------------------------------------------------

     Aby se povelové tabulky moc nerozrůstaly, byly některé
povely shrnuty. Všude tam, kde v rubrice "mnemende" je ,r', může
se povel utvořit spolu s dole uváděným registrem B....A. Aby
se dal zjistit Op-kód žádaného povelu, přičítá se k povelovému
kódu příslušná hodnota registru ,reg' podle uvedené tabulky: 

  ---------------------------------  
  | r | B | C | D | E | H | L | A |  
  ---------------------------------  
  |reg| 0 | 1 | 2 | 3 | 4 | 5 | 7 |  
  ---------------------------------  

     Povel LD A,(8900) "naplní" akumulátor obsahem buňky 8900,
povel LD (8900),A "ukládá" obsah A do paměť. buňky 8900. Pomocí
LD A,B se obsah reg. B přesune do A reg., atd. Pro "naplnění"
akumulátoru nebo střádání v akumulátoru je k dispozici
registračně přímý a nepřímý způsob adresování (viz 4.5).

Příklad:
        přímý :      LD (8900),A      POKE 8900,A

      nepřímý :      LD HL,8900       HL=8900 
                     LD (HL),A        POKE HL,A 

Oba příklady mají stejnou působnost, A je uložen do paměť. buňky
8900. Nepřímé adresování je zde krajně nepříznivé, protože musí
napřed nabrat HL reg. adresou pak teprve je možné "vybrat"
akumulátor. Výhoda nepřímého adresování je však rychlost, když
se plní více paměť. buňek. Dejme tomu, že budeme chtít vymazat
paměť v rozsahu 8900-890f t.j. vložit hodnotu 00.
Při přímém adresování by to vypadalo takto : 

LD A,0        A=0
LD (8900),A   POKE 8900,A
LD (8901),A   POKE 8901,A
LD (8902),A   POKE 8902,A
.             .
.             .
LD (890F),A   POKE 890F,A

str.43

Potřebujeme tedy 16 povelů LD, aby se dal smazat tento rozsah v
paměti. Programujeme-li však počítadlovou smyčku (viz 5.1) a při
tom  použijeme nepřímé adresováni, bude to podstatně příznivější.
Při tom ale potřebujeme povel INC (Increment, česky zvyšuj),
kterým se obsah použitého pointerregistru (viz 4.4) vždy o 1
zvýší.

Příklad:
adresa   kód       povel          analog BASIC 

8000:    21 00 89  LD HL,8900     8000:HL=8900
8003:    06 10     LD B,10        8003:B=10
8005:    3E 00     LD A,00        8005:A=00
8007:    77        LD (HL),A      8007:POKE HL,A
8008:    23        INC HL         8008:HL=HL+1
8009:    10 FC     DJNZ 8007-$    8009:B=B-1:IF B<>0 GOTO 8007
800B:    C9        RET            800B:RETURN

Podstatná část tohoto programu se odehrává mezi 8007 a 8008, tam
je totiž programová smyčka ve které se transferuje obsah
akumulátoru do té paměťové buňky jejíž adresa stojí v HL reg. CPU.
Následně je HL zvýšeno o 1, takže příští paměťovou buňku lze
aktivovat a opakovat smyčku tak často, dokud B nedosáhne 00.
Na záčátku programu je nutno se postarat, aby HL začínalo správnou
adresou, v B reg. bude předem udán počet průběhů smyčky a do A
dána 00, kterou se má doplnit paměťový rozsah. Chcete-li program
vyzkoušet, nezapomeňte do paměťového rozsahu něco zadat, abyste
později poznali zda tento rozsah byl skutečně vymazán. Použité
nepřímé adresování nabízí dvě podstatné přednosti : 
Za prvé je program podstatně kratší než za přímého adresování,
obsazuje pouze 12 bytů místo 51. Za druhé se dají programy napsat
nepřímým adresováním tak, že se dají používat všeobecněji. Můžete
totiž s příkladovým programem vymazat též paměťový rozsah mezi
8920 a 892F. K tomu potřebujete pouze vložit do HL reg. hodnotu
8920 a pak skočit na adresu 8003. Zkuste si to pomocí traceru.
Zadejte HL=8920 a PC=8003 a startujte program. Teď se bude nový
rozsah nulovat.
Příklad:
adresa   kód       povel          Analog BASIC 

8010:    21 20 89  LD HL,8920     8010: HL=8920 
8013:    18 EE     JR 8003-$      8013: goto 8003

Pro nový program, který teď začíná na adr. 8010 a smazává rozsah
mezi 8920 a 892F, potřebovali jsme pouze 5 bytů. Tímto způsobem
se šetří místem v paměti, a čím méně musíme dodatečně programovat,
tím méně se naskytne příležitost udělat chybu. Jako další příklad
vám ukážeme ještě menší program blokového transferu, pomocí
kterého můžete jeden paměťový rozsah překopírovat na jiné místo.

Příklad:
adresa   kód       povel          Analog BASIC 

8000:    7E        LD A,(HL)      8000: A=PEEK (HL)
8001:    12        LD (DE),A      8001: POKE DE,A 
8002:    23        INC HL         8002: HL=HL+1 
8003:    13        INC DE         8003: DE=DE+1 
8004:    10 FA     DJNZ 8000-$    8004: B=B-1 IF B<>0 GOTO 8000 
8006:    C9        RET            8006: RETURN 

str.44

Než odstartujete tento program, musíte ovšem vložit do HL
artovací adresu rozsahu který má být kopírován, dále do DE
startovací adresu, kam se má kopírovat, a do B počet kopírovaných
bytů, naboť jinak byste mohli rozházet a smíchat celou paměť.

Povely blokového transferu 
-------------------------- 
     Protože takové povelové kombinace jako "LD A,(HL)",
"LD (DE),A","INC HL", "INC DE"  se vyskytují velmi často napadlo
fy ZILOG něco velmi užitečného, aby se zkrátily programy a
současně také zrychlily. Toto jsou povely, které vykonávájí
oboje:
transferují byty a současně zvyšují resp. snižují pointery.

-----------------------------------------------------------------
| Mnemonic  | Působení       | Flagy | Hexkód | Analog BASIC    |
|---------------------------------------------------------------|
| Povely blokového transferu (přenosu)                          |
|---------------------------------------------------------------|
| LDI       | (DE)=(HL)      | --0P0-| ED,A0  | POKE DE,PEEK(HL)|
|           | DE=DE+1        |       |        | HL=HL+1:DE=DE+1 |
|           | HL=HL+1,BC=BC-1|       |        | BC=BC-1         |
|           |                |       |        |                 |
| LDIR      | (DE)=(HL)      | --000-| ED,B0  | POKE DE<PEEK(HL)|
|           | DE=DE+1        |       |        | HL=HL+1:DE=DE+1 |
|           | HL=HL+1,BC=BC-1|       |        | BC=BC-1:        |
|           | bis BC=0       |       |        | IF BC<>0 THEN 10|
|           |                |       |        |                 |
| LDD       | (DE)=(HL)      | --0P0-| ED,A8  | POKE DE,PEEK(HL)|
|           | DE=DE-1        |       |        | HL=HL-1:DE=DE-1 |
|           | HL=HL-1,BC=BC-1|       |        | BC=BC-1         |
|           |                |       |        |                 |
| LDDR      | (DE)=(HL)      | --000-| ED,B8  | POKE DE,PEEK(HL)|
|           | DE=DE-1        |       |        | HL=HL-1:DE=DE-1 |
|           | HL=HL-1,BC=BC-1|       |        | BC=BC-1         |
|           | bis BC=0       |       |        | IF BC<>0 THEN 10|
-----------------------------------------------------------------

Při povelech "LDI" a "LDD" ukazuje P-Flag (Parita), zda BC reg.
již je na nule či nikoliv. Když BC <> 0000 je P=1 a když BC=0000
je P=0. Tyto povely jsou velice výkonné, protože paměťové buňky
resp. celé paměťové rozsahy jsou transferovány bez okliky přes
akumulátor.

 LDI  při tom značí "Load and Increment"
 LDD                "Load and Decrement"
 LDIR               "Load Increment and Repeat"
 LDDR               "Load Decrement and Repeat"

Právě popisovaný program blokového transferu se tím dá zkrátit
na jediný povel.
Příklad:
adresa   kód       povel          Analog BASIC 

8000:    ED B0     LDIR           8000: POKE DE,PEEK (HL):
                                  HL=HL+1:DE=DE+1:BC=BC-1:
                                  IF BC<>0 GOTO 8000
8002:    C9        RET            8002: RETURN

str.45

Působení programu zůstává přitom exaktně stejné jako nahoře,
nehledě k tomu, že po provedení jsou Flagy H, P, a N nastaveny
zpět. Počítadlovou proměnnou je tentokrát registrová dvojice BC,
musí se tedy napřed zadat počet průběhů.

16bitové povely plnění a ukládání 
--------------------------------- 

-----------------------------------------------------------------
| Mnemonic  | Působení       | Flagy | Hexkód | Analog BASIC    |
|---------------------------------------------------------------|
| 16 ti bitové nabírací povely (Load)                           |
|---------------------------------------------------------------|
| LD BC,nm  | BC=nm          | ----- | 01,m,n | BC=nm           |
| LD DE,nm  | DE=nm          | ----- | 11,m,n | DE=nm           |
| LD HL,nm  | HL=nm          | ----- | 21,m,n | HL=nm           |
| LD SP,nm  | SP=nm          | ----- | 31,m,n | SP=nm           |
|           |                |       |        |                 |
| LD BC,(nm)| C=(nm),B=(nm+1)| ----- |ED4B,m,n| C=PEEK (nm)     |
|           |                |       |        | B=PEEK (nm+1)   |
| LD DE,(nm)| E=(nm),D=(nm+1)| ----- |ED5B,m,n| E=PEEK (nm)     |
|           |                |       |        | D=PEEK (nm+1)   |
| LD HL,(nm)| L=(nm),H=(nm+1)| ----- | 2A,m,n | L=PEEK (nm)     |
|           |                |       |        | H=PEEK (nm+1)   |
| LD SP,(nm)| SP^L=(nm)      | ----- |ED7B,m,n| SP^L=PEEK (nm)  |
|           | SP^H=(nm+1)    |       |        | SP^H=PEEK (nm+1)|
|---------------------------------------------------------------|
| 16 ti bitové povely střádací                                  |
|---------------------------------------------------------------|
| LD (nm),BC| (nm)=C,(nm+1)=B| ----- |ED43,m,n| POKE nm,C       |
|           |                |       |        | POKE nm+1,B     |
| LD (nm),DE| (nm)=E,(nm+1)=D| ----- |ED53,m,n| POKE nm,E       |
|           |                |       |        | POKE nm+1,D     |
| LD (nm),HL| (nm)=L,(nm+1)=H| ----- | 22,m,n | POKE nm,L       |
|           |                |       |        | POKE nm+1,H     |
| LD (nm),SP| (nm)=SP^L      | ----- |ED73,m,n| POKE nm,SP^L    |
|           | (nm+1)=SP^H    |       |        | POKE nm+1,SP^H  |
| LD SP,HL  | SP=HL          | ----- | F9     | SP=HL           |
-----------------------------------------------------------------
     Působení je i zde velmi zřetelné. Pomocí "LD BC,nm" lze BC
reg. přímo naplnit 16bitovou hodnotou, a sice tak, že do B reg.
se uloží "n" a do C reg. "m". Povelem "LD BC,(nm)" se naplní
C reg. hodnotou z paměťové buňky nm a do B reg. hodnotu z
paměťové buňky nm+1. Pravý opak dělá povel "LD (nm),BC", obsah
C reg. je převeden do paměťové buňky nm a z B reg. do paměťové
buňky nm+1. Věc má však své záludnosti. S povely "LD SP,nm",
"LD SP,(nm)" a "LD SP,HL" by se mělo zacházet velice opatrně.
Těmito povely totiž plníme Stack Pointer SP, který je však stále
potřebný pro CPU, aby bylo možno např. vrátit se z podprogramů
zpět. Neúmyslná změna SP může tedy mít katastrofální následky
a způsobit zhroucení programu. Proto byste prozatím neměli raději
tyto povely vůbec použivat.

str.46

 Plnící a střádací povely se Stackem 
-------------------------------------
     Těmito povely lze odkládat nebo z CPU stacku odebírat zpět
obsahy registrů. Přitom je nutné přihlédnout ke struktuře stacku,
která spočívá na Last-in-First-out (viz 1.2 a 4.1). Protože k
těmto povelům není žádný smysl dávající analog BASIC, neukážeme
také žádný v následující tabulce : 
-----------------------------------------------
| Mnemonic  | Působení       | Flagy | Hexkód |
|---------------------------------------------|
| Stackové povely                             |
|---------------------------------------------|
| PUSH BC   | SP=SP-1,(SP)=B | ----- | C5     |
|           | SP=SP-1,(SP)=C |       |        |
| PUSH DE   | SP=SP-1,(SP)=D | ----- | D5     |
|           | SP=SP-1,(SP)=E |       |        |
| PUSH HL   | SP=SP-1,(SP)=H | ----- | E5     |
|           | SP=SP-1,(SP)=L |       |        |
| PUSH AF   | SP=SP-1,(SP)=A | ----- | F5     |
|           | SP=SP-1,(SP)=F |       |        |
|           |                |       |        |
| POP BC    | C=(SP),SP=SP+1 | ----- | C1     |
|           | B=(SP),SP=SP+1 |       |        |
| POP DE    | E=(SP),SP=SP+1 | ----- | D1     |
|           | D=(SP),SP=SP+1 |       |        |
| POP HL    | L=(SP),SP=SP+1 | ----- | E1     |
|           | H=(SP),SP=SP+1 |       |        |
| POP AF    | F=(SP),SP=SP+1 | ----- | F1     |
|           | A=(SP),SP=SP+1 |       |        |
-----------------------------------------------

Povely PUSH (odlož na stack) můžete odložit obsah reg. na stack.
Obsah registru leží pak nahoře na stacku. Povelem POP (odeber ze
stacku) můžete si odebrat hodnotu, která je na vrchu první a
naplnit jí registr.
     Hodnota, která leží nahoře na stacku se někdy označuje též
jako TOS (Top of Stack - první hodnota na stacku). Často se
používá možnost odkládání obsahů registrů do stacku, zvlášť při
delších programech, protože se velmi brzy ukáže, že CPU registry
již nevystačí a je zapotřebí další registr. Pak se právě odloží
jeden reg. na stack a použije se pro nový účel do té doby, až
budeme potřebovat zase původní obsah registru, který si vezmeme
opět ze stacku zpět.
     Právě tak je nutno před vyvoláním podprogramu "zachraňovat"
obsahy registrů  ze stacku a po návratu z podprogramu je opět
ze stacku vybírat, protože většina podprogramů mění obsahy
registrů.
Příklad:
        Zadejte v test módu A=11, BC=1111, DE=1111, HL=1111,
        F=11111111, IX==1111, IY=1111. Teď startujte s <G> 003E
        <CR> <CR> ještě jednou pípavý podprogram (Beep).
        Pohlédnete-li hned na registry najdete : 
------------------------------------------
|   A:   BC:   DE:   HL:    F: SZ-H-PNC  |
|   00   1111  1111  1111      01000100  |
|                                        |
|              IX:   IY:    PC:    SP:   |
|              1111  1111   003E   A000  |
------------------------------------------

str.47

Uvidíte, že obsah A a F byl podprogramem změněn. Mohou nastat
dosti nepříjemné následky, když se v nějakém vlastním strojovém
programu vyvolá Beep-program a neuvědomíme-li si, že se například
zničí obsah akumulátoru, nebo Flag reg.

     Tedy když dále potřebujeme obsah A a F, napíšeme následující
sekvenci : 
adresa   kód       povel 

8000:    F5        PUSH AF
8001:    CD 3E 00  CALL 3E
8004:    F1        POP AF
8005:    C9        RET

Tím je zaručeno, že obsah A a F zůstane zachován. Vyzkoušejte si
to!!
V případě častější potřeby podprogramu, je výhodné se postarat
v samotném podprogramu o to, aby obsahy registrů zůstávaly pokud
možno zachovány. To se dosáhne povely PUSH na začátku podprogramu
a povely POP na konci podprogramu. Tím způsobem se již nemůsíme
při každém vyvolání podprogramu starat o to, které registry by
byly případně zničeny. Při tom se šetří čas, snižuje se
pravděpodobnost programovacích chyb a zmenšuje se často též
ještě pro program potřebné místo v paměti. Když odložíme více
hodnot na stack, musí se dát pozor na pořadí, protože stack je
zásobník Last-in-First-out, t.j. hodnoty jsou vraceny v obráceném
pořadí, než byly na stack ukládány.

Příklad:
        PUSH BC
        PUSH DE
        PUSH HL
         ..
         ..
        POP HL
        POP DE
        POP BC

     Zde se hodnoty opět naplní do registrů ze kterých byly
odebrány. Jinak je v následujícím příkladě, kde obsahy registrů
BC a DE byly zaměněny.
Příklad:
        PUSH DE
        PUSH BC
         ..
         ..
        POP DE
        POP BC

     Tuto možnost zaměňovat obsahy registrů lze přirozeně též
využít v dobrém smyslu. Dále nutno dbát na to, abyste "stoh"
zanechali vždy tak, jak byl v původním stavu. Všechny hodnoty
které byly na stack odloženy, musí taky zase vrátit zpět. Jinak
se CPU při příštím povelu RET v programu dokonale rozhází. Čeká
tu na vás na nejhořejším místě stacku zpáteční adresa z podprogramu
(viz 5.1) a jestliže místo toho dostanete naservírován nějaký
obsah registru, skočí na nějakou nesmyslnou adresu.

str.48

 5.3 Aritmetické povely 
 ---------------------- 
     Teď přicházíme k početním operacím, které můžete se Z80
provádět. Naprvní pohled je člověk normálně zklamán, jak málo
takový 8bitový procesor vůbec umí. Na druhý pohled pak vidíme
co všechno se s těmito povely dá provádět.

Sčítací povely 
-------------- 
-----------------------------------------------------------------
| Mnemonic  | Působení       | Flagy | Hexkód | Analog BASIC    |
|---------------------------------------------------------------|
| 8mi bitové sčítání                                            |
|---------------------------------------------------------------|
| ADD A,A   | A=A+A          | SZHP0C| 87     | A=A+A           |
| ADD A,B   | A=A+B          | SZHP0C| 80     | A=A+B           |
| ADD A,C   | A=A+C          | SZHP0C| 81     | A=A+C           |
| ADD A,D   | A=A+D          | SZHP0C| 82     | A=A+D           |
| ADD A,E   | A=A+E          | SZHP0C| 83     | A=A+E           |
| ADD A,H   | A=A+H          | SZHP0C| 84     | A=A+H           |
| ADD A,L   | A=A+L          | SZHP0C| 85     | A=A+L           |
| ADD A,n   | A=A+n          | SZHP0C| C6,n   | A=A+n           |
| ADD A,(HL)| A=A+(HL)       | SZHP0C| 86     | A=A+PEEK (HL)   |
|           |                |       |        |                 |
| ADC A,A   | A=A+A+C        | SZHP0C| 8F     | A=A+A+C         |
| ADC A,B   | A=A+B+C        | SZHP0C| 88     | A=A+B+C         |
| ADC A,C   | A=A+C+C        | SZHP0C| 89     | A=A+C+C         |
| ADC A,D   | A=A+D+C        | SZHP0C| 8A     | A=A+D+C         |
| ADC A,E   | A=A+E+C        | SZHP0C| 8B     | A=A+E+C         |
| ADC A,H   | A=A+H+C        | SZHP0C| 8C     | A=A+H+C         |
| ADC A,L   | A=A+L+C        | SZHP0C| 8D     | A=A+L+C         |
| ADC A,n   | A=A+n+C        | SZHP0C| CE,n   | A=A+n+C         |
| ADC A,(HL)| A=A+(HL)+C     | SZJP0C| 8E     | A=A+PEEK (HL)+C |
-----------------------------------------------------------------

     Symbolika (mnemonic) těchto povelů se vysvětluje následovně:
"ADD" znamená prostě sečti,  "ADC" znamená (Add with carry, česky
sečti s přenosem).
Příklad:
adresa   kód       povel          Analog BASIC 

8000:    83        ADD A,E        8000: A=A+E 
8001:    C9        RET            8001: RETURN

Pomocí tohoto krátkého povelového sledu se obsah reg. E přičte
k akumulátoru a je v akumulátoru uložen. Vyzkoušejte si to s
učebním souborem tak, že zadáte např. DE=0005 a A=03 a startujete
program. Následně má A hodnotu 08. Pozorujete-li působení povelu
ADC, budete se nejprve ptát, proč je obsah Carry Flagu C (tedy
0 nebo 1) vždy spolu sečten. Ale přičítání Carry Flagu je
rafinovanou záležitostí, tím totiž lze při sečítání vícemístných
čísel přenos přesunout z jednoho byte na další (viz 1.5). A to
se děje následovně : 
Při sečítání dvou 8bitových hodnot, jak tomu je v právě uvedeném
příkladu, se může vyskytnout přenos na 9.bit, např. když se budou
sečítat následující hodnoty.

str.49

Příklad:
        hexadecimál     decimál    binár
        DE=FF           255        11111111
        A =05             5        00000101

Výsledek součtu je pak exaktně:

           104          260       100000100

Akumulátor může však pojmout pouze 8 bitů a obsahuje po součtu:

         A=04             4       00000100

Na dvojkovém znázornění vidíte, že v akumulátoru byla právě
první 1 přehozena. Tato 1 stojí po součtu v Carry Flagu. Tuto
skutečnost teď můžeme použít abychom buď signalizovali chybu
přeběhnutí podmíněným skokovým povelem k běžnému postupu při
chybě, nebo abychom tuto 1 v Carry použili k přenosu na další
místo. Poslední pak jde automaticky s povelem ADC, protože při
sčítání dalších míst se Carry přece automaticky přidává.
Následující program sečítá registr DE s reg. HL a ukládá výsledek
do registru HL (HL=HL+DE).
Příklad:
adresa   kód       povel          Analog BASIC 

8000:    7D        LD A,L         8000:A=L
8001:    83        ADD A,E        8001:A=A+E
8002:    6F        LD L,A         8002:L=A
8003:    7C        LD A,H         8003:A=H
8004:    8A        ADC A,D        8004:A=A+D+C
8005:    67        LD H,A         8005:H=A
8006:    C9        RET            8006:RETURN

Vidíte že stejně jako u písemného  sečítání se začíná od zadu,
sčítají se nejdříve L byty. Jako další se pak sečtou H byty,
přičemž se zohledňuje přenos z L bytu, protože stojí ještě v C
Flagu.

    Vyzkoušejte si program, že zadáte HL=00FF a DE=0005. Najdete
pak správný výsledek HL=0104.
-----------------------------------------------------------------
| Mnemonic  | Působení       | Flagy | Hexkód | Analog BASIC    |
|---------------------------------------------------------------|
| 16ti bitový součet                                            |
|---------------------------------------------------------------|
| ADD HL,BC | HL=HL+BC       | --H-0C| 09     | HL=HL+BC        |
| ADD HL,DE | HL=HL+DE       | --H-0C| 19     | HL=HL+DE        |
| ADD HL,HL | HL=HL+HL       | --H-0C| 29     | HL=HL+HL        |
| ADD HL,SP | HL=HL+SP       | --H-0C| 39     | HL=HL+SP        |
|           |                |       |        |                 |
| ADC HL,BC | HL=HL+BC+C     | SZHV0C| ED,4A  | HL=HL+BC+C      |
| ADC HL,DE | HL=HL+DE+C     | SZHV0C| ED,5A  | HL=HL+DE+C      |
| ADC HL,HL | HL=HL+HL+C     | SZHV0C| ED,6A  | HL=HL+HL+C      |
| ADC HL,SP | HL=HL+SP+C     | SZHV0C| ED,7A  | HL=HL+SP+C      |
-----------------------------------------------------------------

str.50

     Zde je symbolika stejná jako u 8bitových součtových povelů,
avšak sečítají se 16-ti bitové hodnoty k HL registru. 16bitové
součtové povely se používají hlavně při přepočtu adres, lze je
však právě tak dobře použít pro součet větších binárních čísel.
Shora uvedený součtový program vypadá s 16bitovými součtovými
povely takto : 
Příklad:
adresa   kód       povel          Analog BASIC 

8000:    19        ADD HL,DE      8000: HL+DE 
8001:    C9        RET            8001: RETURN 

 Součet negativních čísel 
 ------------------------ 
     Zadejte HL=0109 a DE=FFFF a startujte ještě jednou poslední
program. V HL najdete teď hodnotu 0108, protože výsledek teď
přesahuje 16 bitů. Však pohleďte blíže na výsledek. Účinek součtu
FFFF je patrně tentýž jako při odečtu 1:
0109-1=0108.
Zadejte DE=FFFE, hodnotu pro HL nechte stát a startujte znovu.
Najdete výsledek HL=0106, tedy subtrakce od 2. Tento sled věcí
se využívá při znázorňování negativních 16bitových čísel. Vezmeme
místo 1 hodnotu FFFF, namísto 2 hodnotu FFFE, namísto 3 hodnotu
FFFD,.... Tento způsob se nazývá komplementární dvojice (viz
dodatek A3). Získáme komplementární dvojici 16bitového čísla
tím, že se toto číslo odečte od hex 10000: -9 je v komplementární
dvojici 10000-9=FFFF7.
Normálně se rozděluje rozsah u 16bitových čísel s předznaménkem
takto : 
                       0000 až 7FFF    Odpovídá pozitivním
                       číslům 0 až 32767

                       FFFF až 8000    Odpovídá negativním
                       číslům -1 až -32768

Přesně stajný trik lze použít u 8bitových hodnot : 
                       00 až 7F        Odpovídá 0 až 127

                       FF až 80        Odpovídá -1 až -128

     Na tomto způsobu vyjadřování čísel je praktická ta
skutečnost, že u všech součtů ve strojovém jazyce zohledňuje
automaticky správné předznaménko. Teď rozumíte také funkci
V Flagu. Tento Flag je nastaven, když se při součtu čísel s
předznaménkem překročí hodnotový rozsah. Když např. k 7F se
přičte 1, což dává výsledek 80. Jednalo-li se však o čísla s
předznaménkem, byla k 127 přičtena 1, což dává 128. 128 však není
jako 8bitové číslo s předznamenáním již vytvořitelné, výsledek
80=-128 je nesmysl. A právě toto hlásí V Flag CPU, pročež je
také nazýván "přetokoý flag" (overflow).

str.51

32-bitový součet
----------------
     Po této exkurzi k negativním číslům, chceme vám představit
ještě program sčítání 32 bitových čísel. Rozsah hodnot výsledku
je již přitom mezi 0 a 4,294,967,295. Sečítaná čísla mají být
ukládána v rozsahu adres 8100...8103 a 8104...8107, výsledek
součtu pak ukládán do 8100...8103. Čísla obsazují tedy vždy 4
byty. Teď vám neudáme žádný Analog BASIC, nýbrž raději budeme
program komentovat.

Příklad:

adresa   kód       povel       komentář

8000:    A7        AND A       vysaď Carry=0
8001:    11 03 81  LD DE,8103  1.číslo a výsledek
8004:    21 07 81  LD HL,8107  2.číslo
8007:    06 04     LD B,04     počet bytů
8009:    1A        LD A,(DE)   1.číslo nabrat
800A:    8E        ADC A,(HL)  2.číslo sečíst
800B:    12        LD (DE),A   výsledk uložit
800C:    1B        DEC DE      1.číslo na příští byte
800D:    2B        DEC HL      2.číslo na příští byte
800E:    10 F9     DJNZ 8009-$ opakovat od 8009
8010:    C9        RET
     Je sčítáno ve smyčce mezi 8009 a 800F. Napřed se nabírá
jeden byte druhým číslem, pak jeden byte prvního čísla je sečten
a výsledek uložen ve stejném místě. Potom se sníží pointerreg.
DE a HL. Aby se na začátku současně nasečetl žádný přenos, stojí
povel AND A na začátku programu. Nechává akumulátor beze změny
a nastaví pouze Flagy (Carry=0). To je nutné, protože Z-80 nemá
žádný povel CLC (Clear Carry). Nejlépe bude, když si vyzkoušíte
program a projedete průběh po jednotlivých krocích. Proto vložte
například do pamětových buňek 8100...8103 číslo 11 22 33 44 a do
buňek 8104...8107 číslo 99 AA BB CC. Nakonec najdete výsledek v
paměťových buňkách 8100...8103 : AA CC EF 10. Teď také vidíte,
proč je tak důležité, že povel DJNZ neovlivňuje Carry flag. V
programové smyčce se provádí v Carry flagu přesun přenosu při
součtu na příští.

Korektura BCD
-------------
     Zatím jsme pracovali pouze s dvojkovými čísly, naše CPU ale
umí taky provádět součty decimálně. Při tom používá vyjádření
BCD (Binary Coded Decimal, česky dvojkově kódované decimální).

----------------------------------------------|
| Mnemonic  | Působení       | Flagy | Hexkód |
|---------------------------------------------|
| DAA       | přizpůsob A    | SZHP-C| 27     |
|           | decimálně      |       |        |
-----------------------------------------------
     DAA znamená "Decimal adjust Accumulator, česky přízpůsob
akumulátor decimálně". Tento povel musí být řazen bezprostředně
po sčítacím nebo odečítacím povelu, protože se dotazuje na N- a
H- Flag. V BCD systému se decimální čísla znázorňují následovně
(viz dodatek A3). Pro každou decimální cifru se použije 4 bity,
tedy půl bytu. V těchto čtyřech bitech se cifry 0...9 vyjadřují
zcela normálně jako dvojková hodnota, tedy např. 9 jako 1001.
Rozdíl vůči dosud užívanému šestnáctkovému vyjádření spočívá v
tom, že hodnoty A...F jsou zakázané a jsou dovoleny pouze 0 až
9. Nejvyšší hodnota v jednom byte je přitom 99 a nikoli již FF.
Transport přenosu pomocí Carry bitu funguje právě tak jako u
dvojkových čísel.

str.52

Součet 8mi místných čísel
-------------------------
     Protože všechno probíhá jako při dvojkovém součtu, můžete
vzít poslední příklad (32bitový součet) a z toho udělat program
na sčítání 8mi místných decimálních čísel. K tomu se jen musí
vložit po povelu ADC povel DAA. Program pak vypadá takto:

Příklad:

adresa   kód       povel          komentář

8000:    A7        AND A          nasdtav Carry=0
8001:    11 03 81  LD DE,8103     1.číslo a výsledek
8004:    21 07 81  LD HL,8107     2.číslo
8007:    06 04     LD  B,04       počet bytů
8009:    1A        LD A,(DE)      1.číslo nabrat
800A:    8E        ADC A,(HL)     2.číslo sečíst
800B:    27        DAA            BCD-přizpůsobení
800C:    12        LD (DE),A      výsledek uložit
800D:    1B        DEC DE         1.číslo na příští byte
800E:    2B        DEC HL         2.číslo na příští byte
800F:    10 F8     DJNZ 8009-$    opakuj od 8009
8011:    C9        RET

Vložíte-li pak do 8100...8103 číslo 12309999 a do 8104...8107
číslo 30000001, najdete po proběhnutí programu výsledek v 8100.
..8103 : 42310000. Vidíte zřetelně, že bylo sčítáno decimálně
protože jinak byste nalezli výsledek 4230999A.


