Breve riferimento alle istruzioni
By Claudio Fin

Caricamento valori a 8 bit
Incrementi e decrementi a 8 e 16 bit
Aritmetica a 8 bit e confronti
Operatori logici
Caricamento valori a 16 bit
Operazioni sullo stack
Aritmetica a 16 bit
Cicli e salti
Subroutine
Operazioni su blocchi di dati
Scambi tra registri
Bit, set e reset
Gestione interrupt e CPU
Rotazioni e shift
Ingresso/uscita
Altre istruzioni
Ist. "non documentate"
Le istruzioni sono scritte in forma abbreviata, e vanno fatte le seguenti sostituzioni:
r    = registri A B C D E H L  rr  = registri BC DE HL
idx
  = registri IX IY          cc  = condizione C M NC NZ P PE PO Z
port
= valore 8 bit            dis = valore 8 bit con segno (da +127 a -128)
b    = 0..7                    p   = 00H 08H 10H 18H 20H 28H 30H 38H
ADDR = indirizzo 16 bit        n   = valore 8 bit    nn = valore 16 bit

dis (displacement o spiazzamento) è un valore a 8 bit che viene
considerato dalla CPU come un valore a 7 bit più il segno.
I valori da 0 a 127 vengono considerati positivi, mentre quelli
da 128 a 255 sono considerati negativi e scritti in complemento a 2.
I valori negativi validi vanno da -1 a -128. Per calcolare il valore di
un dis negativo è sufficiente calcolare 256-valore, esempio: -57 = 256-57 = 199.
Gli effetti sui flag sono da intendere nel seguente modo:
  - = nessun cambiamento
  1 = flag posto a 1
  0 = flag posto a zero
  # = flag cambiato in accordo con il risultato
  ? = stato incerto. 

Il tempo di esecuzione è espresso in cicli di clock, a 4 Mhz 4 cicli corrispondono a 1 microsecondo. 

Caricamento valori a 8 bit

Mnemonico     Tempo   Effetto sui flag    Operazione
                      C  Z  PV  S  N  H

LD r,r          4     -  -   -  -  -  -   r=r
LD r,n          7     -  -   -  -  -  -   r=n

LD A,(ADDR)    13     -  -   -  -  -  -   A=(ADDR)
LD (ADDR),A    13     -  -   -  -  -  -   (ADDR)=A

LD r,(HL)       7     -  -   -  -  -  -   r=(HL)
LD A,(BC)       7     -  -   -  -  -  -   A=(BC)
LD A,(DE)       7     -  -   -  -  -  -   A=(DE)
LD (HL),r       7     -  -   -  -  -  -   (HL)=r
LD (BC),A       7     -  -   -  -  -  -   (BC)=A
LD (DE),A       7     -  -   -  -  -  -   (DE)=A

LD r,(idx+dis) 19     -  -   -  -  -  -   r=(idx+dis)
LD (idx+dis),r 19     -  -   -  -  -  -   (idx+dis)=r

LD (HL),n      10     -  -   -  -  -  -   (HL)=n
LD (idx+dis),n 19     -  -   -  -  -  -   (idx+dis)=n
LD (load o carica) si deve intendere sempre nella forma
"carica dove,cosa", ad esempio LD B,L significa
carica nel registro B il valore del registro L.

Le parentesi tonde indicano il contenuto di una cella di memoria
indirizzata (o puntata) dal contenuto delle parentesi. Ad esempio
LD A,(30000) significa "carica in A il contenuto della cella di
memoria di indirizzo 30000", ed è l'equivalente del "PEEK(30000)"
in BASIC. LD A,(HL) significa "carica in A il contenuto della
cella di memoria il cui indirizzo è dato dal valore di HL" (o
puntata da HL).

Le istruzioni di caricamento tramite i registri indice IX e IY
richiedono che sia specificato un valore, che indica quanti
byte più avanti o più indietro deve puntare il processore
rispetto all'indirizzo specificato in IX o IY.

Incrementi/decrementi a 8 e 16 bit

Mnemonico     Tempo   Effetto sui flag    Operazione
                      C  Z  PV  S  N  H

INC r           4     -  #   #  #  0  #   r=r+1
INC (HL)       11     -  #   #  #  0  #   (HL)=(HL)+1
INC (idx+dis)  23     -  #   #  #  0  #   (idx+dis)=(idx+dis)+1

INC rr          6     -  -   -  -  -  -   rr=rr+1
INC idx        10     -  -   -  -  -  -   idx=idx+1

DEC r           4     -  #   #  #  1  #   r=r-1
DEC (HL)       11     -  #   #  #  1  #   (HL)=(HL)-1
DEC (idx+dis)  23     -  #   #  #  1  #   (idx+dis)=(idx+dis)-1

DEC rr          6     -  -   -  -  -  -   rr=rr-1
DEC idx        10     -  -   -  -  -  -   idx=idx-1
NOTA: Il flag di zero viene settato se il risultato di un incremento
o decremento a 8 bit è 0. Incrementi e decrementi a 16 bit non
alterano il valore dei flags.

Anche qui le parentesi tonde indicano una cella di memoria puntata
dal loro contenuto: INC HL significa "incrementa di 1 il valore del
registro HL", INC (HL) significa "incrementa di 1 il valore della
cella di memoria puntata da HL".

Aritmetica a 8 bit e confronti

Mnemonico      Tempo   Effetto sui flag    Operazione
                       C  Z  PV  S  N  H

ADD A,r          4     #  #   #  #  0  #   A=A+r
ADD A,n          7     #  #   #  #  0  #   A=A+n
ADD A,(HL)       7     #  #   #  #  0  #   A=A+(HL)
ADD A,(idx+dis) 19     #  #   #  #  0  #   A=A+(idx+dis)

ADC A,r          4     #  #   #  #  0  #   A=A+r+FlagCarry
ADC A,n          7     #  #   #  #  0  #   A=A+n+FlagCarry
ADC A,(HL)       7     #  #   #  #  0  #   A=A+(HL)+FlagCarry
ADC A,(idx+dis) 19     #  #   #  #  0  #   A=A+(idx+dis)+FlagCarry

SUB r            4     #  #   #  #  1  #   A=A-r
SUB n            7     #  #   #  #  1  #   A=A-n
SUB (HL)         7     #  #   #  #  1  #   A=A-(HL)
SUB (idx+dis)   19     #  #   #  #  1  #   A=A-(idx+dis)

SBC A,r          4     #  #   #  #  1  #   A=A-r-FlagCarry
SBC A,n          7     #  #   #  #  1  #   A=A-n-FlagCarry
SBC A,(HL)       7     #  #   #  #  1  #   A=A-(HL)-FlagCarry
SBC A,(idx+dis) 19     #  #   #  #  1  #   A=A-(idx+dis)-FlagCarry

CP  r            4     #  #   #  #  1  #   A-r
CP  n            7     #  #   #  #  1  #   A-n
CP (HL)          7     #  #   #  #  1  #   A-(HL)
CP (idx+dis)    19     #  #   #  #  1  #   A-(idx+dis)
Le istruzioni ADD e SUB sommano o sottraggono da A l'operando
specificato, il risultato è posto in A.

Le istruzioni ADC e SBC tengono conto del valore del flag di carry
che viene usato come riporto/prestito.

L’istruzione cp (compare o confronta) effettua una sottrazione
tra A e un valore o registro da confrontare. Questo confronto non
altera il valore di A ma modifica i flag in base al risultato, il
flag C settato indica che il numero confrontato è maggiore di A,
il flag Z settato indica che il numero confrontato è uguale,
nessuno dei due flag settati indica che il numero è minore.

TRUCCO: per controllare se il valore di un registro a 8 bit è
zero senza confrontarlo con A, lo si può incrementare e
decrementare subito, se il registro era zero torna a zero e
il flag Z viene settato.

Operatori logici

Mnemonico     Tempo   Effetto sui flag    Operazione
                      C  Z  PV  S  N  H

AND r           4     0  #   #  #  0  1   A=A AND r
AND n           7     0  #   #  #  0  1   A=A AND n
AND (HL)        7     0  #   #  #  0  1   A=A AND (HL)
AND (idx+dis)  19     0  #   #  #  0  1   A=A AND (idx+dis)

OR  r           4     0  #   #  #  0  0   A=A OR r
OR  n           7     0  #   #  #  0  0   A=A OR n
OR  (HL)        7     0  #   #  #  0  0   A=A OR (HL)
OR  (idx+dis)  19     0  #   #  #  0  0   A=A OR (idx+dis)

XOR r           4     0  #   #  #  0  0   A=A XOR r
XOR n           7     0  #   #  #  0  0   A=A XOR n
XOR (HL)        7     0  #   #  #  0  0   A=A XOR (HL)
XOR (idx+dis)  19     0  #   #  #  0  0   A=A XOR (idx+dis)
Le istruzioni logiche effettuano l'operazione logica tra A e l'operando
specificato, il risultato è posto in A.

Queste operazioni sono da intendersi sui singoli bit, D0 di A con D0
dell' operando, D1 di A con D1 dell'operando e così via. Ad esempio se
A vale 00100110, effettuare un OR con 00001111 porta A a 00101111.
Effettuare invece un AND 00001111 porta A a 00000110, effettuare uno 
XOR 11110000 porta A a  11010110.

Tutte le istruzioni logiche azzerano il flag di carry. Dato che non
esiste un’istruzione apposita per azzerarlo si può usare l’istruzione
AND A che non altera il contenuto di A.

L'istruzione LD A,0 può in molti casi essere sostituita da XOR A che
è più veloce e richiede meno memoria. L'accumulatore messo in XOR
con se stesso diventa infatti zero, attenzione solo che lo XOR
influenza i flags mentre LD no, perciò se il valore dei flags è
importante non si deve usare questo metodo per azzerare l'accumulatore.

Caricamento valori a 16 bit

Mnemonico     Tempo   Effetto sui flag    Operazione
                      C  Z  PV  S  N  H

LD rr,nn       10     -  -   -  -  -  -   rr=nn
LD idx,nn      14     -  -   -  -  -  -   idx=nn

LD (ADDR),BC   20     -  -   -  -  -  -   (ADDR)=BC
LD (ADDR),DE   20     -  -   -  -  -  -   (ADDR)=DE
LD (ADDR),HL   16     -  -   -  -  -  -   (ADDR)=HL
LD (ADDR),idx  20     -  -   -  -  -  -   (ADDR)=idx

LD BC,(ADDR)   20     -  -   -  -  -  -   BC=(ADDR)
LD DE,(ADDR)   20     -  -   -  -  -  -   DE=(ADDR)
LD HL,(ADDR)   16     -  -   -  -  -  -   HL=(ADDR)
LD idx,(ADDR)  20     -  -   -  -  -  -   idx=(ADDR)
Anche per i caricamenti a 16 bit LD si deve intendere sempre nella
forma "carica dove,cosa". I valori trasferiti in questo caso sono
una coppia di byte considerati assieme come una word di 16 bit.

NOTA IMPORTANTE: In memoria tutti i valori a 16 bit (2 byte) sono
scritti nel formato basso/alto, è cioè scritto per primo il byte
meno significativo e poi quello puù significativo. Per esempio
prendiamo l’istruzione LD HL,25000. Il codice macchina in 
esadecimale di questa istruzione è 21XXXX, dove al posto di XXXX
vanno scritti i due byte che rappresentano il 25000. In esadecimale
25000 è 61A8, l’istruzione scritta in memoria è perciò: 21A861.

L'istruzione LD BC,45000 carica in BC il valore 45000. Visto che
B contiene il byte più significativo della word e C quello meno
significativo, lo stesso risultato si può ottenere anche scrivendo
le due istruzioni separate LD B,175 e LD C,200 (175*256+200=45000).

L'istruzione LD BC,(45000) carica in BC la word contenuta nei
due byte di memoria di indirizzo 45000 e 45001. In C finisce il
valore della cella 45000 e in B quello della cella 45001 (formato
basso/alto).

Operazioni sullo stack

Mnemonico     Tempo   Effetto sui flag    Operazione
                      C  Z  PV  S  N  H

PUSH AF        11     -  -   -  -  -  -   (SP-1)=A         (SP-2)=F        SP=SP-2
PUSH rr        11     -  -   -  -  -  -   (SP-1)=r(high)   (SP-2)=r(low)   SP=SP-2
PUSH idx       15     -  -   -  -  -  -   (SP-1)=idx(high) (SP-2)=idx(low) SP=SP-2
POP  AF        10     -  -   -  -  -  -   F=(SP)           A=(SP+1)        SP=SP+2
POP  rr        10     -  -   -  -  -  -   r(low)=(SP)    r(high)=(SP+1)    SP=SP+2
POP  idx       14     -  -   -  -  -  -   idx(low)=(SP)  idx(high)=(SP+1)  SP=SP+2





LD SP,ADDR     10     -  -   -  -  -  -   SP=ADDR
LD SP,(ADDR)   20     -  -   -  -  -  -
LD SP,HL        6     -  -   -  -  -  -   SP=HL
LD SP,idx      10     -  -   -  -  -  -   SP=idx

INC SP          6     -  -   -  -  -  -   SP=SP+1
DEC SP          6     -  -   -  -  -  -   SP=SP-1

ADD HL,SP      11     #  -   -  -  0  #   HL=HL+SP
ADD idx,SP     15     #  -   -  -  0  #   idx=idx+SP

ADC HL,SP      15     #  #   #  #  0  #   HL=HL+SP+FlagCarry

SBC HL,SP      15     #  #   #  #  1  #   HL=HL-SP-FlagCarry

EX (SP),HL     19     -  -   -  -  -  -   L<->(SP)   H<->(SP+1)
EX (SP),idx    23     -  -   -  -  -  -   idx(low)<->(SP)  idx(high)<->(SP+1)
Con le istruzioni PUSH si inseriscono dei valori a 16 bit sulla cima
dello stack, con le istruzioni POP si estraggono. L'istruzione PUSH
non cambia il valore del registro, ne effettua solo una copia nello
stack.

Lo stack può essere utile per salvare temporaneamente il valore
di uno o più registri e ripristinarlo poi più tardi:

    PUSH BC  ;salva il valore di BC
     ....altre istruzioni....
    POP BC   ;recupera il valore di BC

Oppure può servire per assegnare a un registro a 16 bit il valore di
un altro registro a 16 bit:

    PUSH BC  ;inserisce il valore di BC sullo stack
    POP IX   ;lo estrae e lo assegna a IX

O ancora può servire a scambiare tra loro i valori di due registri
a 16 bit:

    PUSH DE  ;inserisce il valore di DE sullo stack
    PUSH IY  ;Inserisce il valore di IY sullo stack
    POP DE   ;lo estrae e lo assegna a DE
    POP IY   ;estrae il vecchio valore di DE e lo assegna a IY

Alla fine il numero di POP deve euguagliare il numero di PUSH.

L'istruzione PUSH AF permette di salvare sullo stack anche il
registro dei flag, e questo serve se è importante mantenere
inalterati i flag ma si devono anche eseguire delle istruzioni
che li modificano:

    PUSH AF  ;salva il valore di AF
     ....altre istruzioni....
    POP AF   ;recupera AF, i flag tornano al vecchio valore

Tutte le altre istruzioni che coinvolgono il registro SP (stack
pointer) possono essere ignorate, in quanto servono per una
gestione complessa dello stack quale ad esempio il passaggio
parametri tra subroutine attraverso lo stack stesso ecc...
L'unica da prendere in considerazione in sistemi semplici è
LD SP,indirizzo che permette di porre la testa dello stack
in una posizione nota, ad esempio all'ultimo indirizzo della RAM.

Aritmetica a 16 bit

Mnemonico     Tempo   Effetto sui flag    Operazione
                      C  Z  PV  S  N  H

ADD HL,rr      11     #  -   -  -  0  #   HL=HL+rr
ADD idx,BC     15     #  -   -  -  0  #   idx=idx+BC
ADD idx,DE     15     #  -   -  -  0  #   idx=idx+DE
ADD IX,IX      15     #  -   -  -  0  #   IX=IX+IX
ADD IY,IY      15     #  -   -  -  0  #   IY=IY+IY

ADC HL,rr      15     #  #   #  #  0  #   HL=HL+rr+FlagCarry

SBC HL,rr      15     #  #   #  #  1  #   HL=HL-rr-FlagCarry
Le istruzioni aritmetiche a 16 bit sono poche, HL svolge la
funzione di "accumulatore a 16 bit", pertanto il risultato
di una somma o sottrazione finisce in HL.

La sottrazione è solo con riporto, quindi se si devono
sottrarre due registri e si vuole essere sicuri che non
ci sia un riporto (anzi un prestito) impostato allora
si deve prima azzerare il flag di carry con AND A o OR A,
e poi effettuare la SBC:

    SBC HL,DE  ;sottrae DE da HL e tiene conto del flag di carry

    AND A
    SBC HL,DE  ;sottrae DE da HL con flag di carry a 0

Cicli e salti

Mnemonico     Tempo   Effetto sui flag    Operazione
                      C  Z  PV  S  N  H

JP ADDR        10     -  -   -  -  -  -   PC=ADDR
JP (HL)         4     -  -   -  -  -  -   PC=HL
JP (idx)        8     -  -   -  -  -  -   PC=idx
JP cc,ADDR     10     -  -   -  -  -  -   se cc vera  PC=ADDR

JR dis         12     -  -   -  -  -  -   PC=PC+dis
JR C,dis       12 cc vera 7 cc falsa  -   se FlagCarry=1 PC=PC+dis
JR NC,dis      12 cc vera 7 cc falsa  -   se FlagCarry=0 PC=PC+dis
JR Z,dis       12 cc vera 7 cc falsa  -   se FlagZero=1  PC=PC+dis
JR NZ,dis      12 cc vera 7 cc falsa  -   se FlagZero=0  PC=PC+dis

DJNZ dis       13 se B>0 8 se B=0  -  -   B=B-1   se B>0 allora PC=PC+dis

Le condizioni possibili per cc sono C M NC NZ P PE PO Z
L'istruzione JP (jump, salta) è l'equivalente del GOTO del BASIC.
JP cc tiene conto della condizione specificata, ad esempio JP Z,32000
significa: "se il flag di zero è settato salta all'indirizzo 32000",
a questo indirizzo devono naturalmente esserci delle istruzioni valide
da eseguire. Si può saltare a un qualsiasi punto della memoria e la
CPU esegue comunque i byte che trova considerandoli come istruzioni
valide.

JR è un salto corto (o relativo) e permette di saltare avanti o
indietro rispetto alla posizione corrente. Il massimo salto in avanti
è di 127 byte, il massimo salto all'indietro è di -128 byte.

Anche JR può essere associato a una condizione e saltare solo se
un certo flag è settato o resettato, i salti associati a una condizione
sono detti "salti condizionati", quelli senza condizione sono detti
"incondizionati".

NOTA: Quando si deve calcolare il valore numerico da assegnare a un
salto corto si deve tenere presente che il program counter punta
sempre al primo byte dell'istruzione successiva a quella di salto,
e che i valori negativi vanno scritti in complemento a 2.

L'istruzione DJNZ (decrementa e jump se non zero) consente di creare
facilmente un loop usando il registro B come contatore delle iterazioni
(passaggi). Questa istruzione infatti decrementa il valore di B e se
non è arrivato a zero salta di un certo numero di byte avanti o
indietro rispetto alla posizione corrente, proprio come con JR NZ,..

L'esempio seguente mostra come eseguire 45 volte un gruppo di
istruzioni:

         LD B,45
SALTO1   ..... istruzioni .....
         ..... istruzioni .....
         ..... istruzioni .....
         DJNZ SALTO1

Se le istruzioni modificano il valore del registro B o BC allora
è necessario salvare BC nello stack prima di esse, e recuperarlo
alla fine prima del DJNZ:

         LD B,45
SALTO1   PUSH BC          ;salva il valore di BC nello stack
         ..... istruzioni .....
         ..... istruzioni che alterano B o BC .....
         ..... istruzioni .....
         POP BC           ;recupera il vecchio valore di BC
         DJNZ SALTO1

NOTA: impostando B=1 si ottiene un solo passaggio, impostando B=2
si ottiene una ripetizione (quindi due passaggi), impostando B=255
si ottengono 255 passaggi, impostando B=0 si ottengono 256 passaggi.

Se occorre realizzare cicli con più di 256 iterazioni si possono
nidificare più strutture DJNZ, l'esempio seguente realizza 75000
iterazioni (300*250=75000):

         LD B,300
SALTO1   PUSH BC
         LD B,250
SALTO2   PUSH BC
         ..... istruzioni .....
         ..... istruzioni .....
         ..... istruzioni .....
         POP BC
         DJNZ SALTO2
         POP BC
         DJNZ SALTO1

Subroutine

Mnemonico     Tempo   Effetto sui flag    Operazione
                      C  Z  PV  S  N  H

CALL ADDR      17     -  -   -  -  -  -   (SP-1)=PC(alto) (SP-2)=PC(basso)
                                          SP=SP-2 PC=ADDR
CALL cc,ADDR   17 cc vera 10 cc falsa -   come sopra ma solo se cc vera
RET            10     -  -   -  -  -  -   PC(basso)=(SP) PC(alto)=(SP+1) SP=SP+2
RET cc         11 cc vera 5 cc falsa  -   come sopra ma solo se cc vera

RST P          11     -  -   -  -  -  -   come CALL p

I valori ammessi per p in un’istruzione RST sono 00H 08H 10H 18H 20H 28H 30H 38H
L'istruzione CALL è equivalente alla GOSUB del BASIC e serve per
chiamare una subroutine. RET termina la subroutine come il RETURN
del BASIC. Quando viene eseguita una CALL il valore del program
cpunter viene salvato sullo stack e sostituito con il valore
specificato nell'istruzione. Quando viene eseguita una RET viene
estratto dallo stack l'indirizzo ed assegnato al program counter.
All'interno di una subroutine si deve stare attenti a non dimenticare
neppure un byte nello stack, altrimenti al momento del RET la CPU
al posto dell'indirizzo che aveva depositato trova un altro valore.

Sia le chiamate a subroutine che i ritorni possono essere associati
a una condizione, ad esempio CALL Z,indirizzo significa "se il flag
di zero è settato allora chiama la subroutine all'indirizzo
specificato". Come per i jump (JP) anche le CALL possono puntare a
qualsiasi indirizzo di memoria, è cura del programmatore far si che
un JP o una CALL puntino a istruzioni valide.

Il seguente esempio mostra come chiamare tre diverse subroutine a seconda
del valore di A:

              LD A,valore da 1 a 3

              CP 1
              CALL Z,subroutine1
              CP 2
              CALL Z,subroutine2
              CP 3
              CALL Z,subroutine3

NOTA: In questo esempio è importante che le subroutine non modifichino
il valore di A, altrimenti al loro ritorno potrebbe essere richiamata
anche una delle altre.

L'uso delle subroutine è un'ottima scelta programmativa. Ogni subroutine
dovrebbe effettuare un solo compito nella maniera più efficiente
possibile, e dovrebbe essere vista come una piccola "scatola nera" da
chiamare per ottenere il suo servizio. In questo modo è più semplice
scrivere, testare e modificare il programma o trovarne gli errori.
Inoltre ci si può concentrare su singoli aspetti del problema (o
sottofunzioni) senza dover avere sempre in mente l'intero programma.
Il programma stesso può essere pensato e sviluppato come una serie di
piccoli moduli indipendenti da collegare poi assieme tramite opportune
CALL. Questo tipo di ordine è importante in qualsiasi linguaggio, ma lo
è ancora di più quando si lavora con l'assembler, perché in questo
caso è molto più facile incorrere in errori difficilmente individuabili.

L'istruzione RST (restart) è stata mantenuta dallo Z80 per compatibilità
con l'8080. E'equivalente a una CALL, solo che è più veloce ad essere
eseguita e richiede solo un byte di memoria (contro i 3 di una CALL).
Per contro può saltare solo a 8 indirizzi fissi distanti 8 byte l'uno
dall'altro a partire dall'inririzzo zero.

Una RST 00H fa ripartire il programma dall'indirizzo zero, cioè dall'
indirizzo a cui punta la CPU all'accensione o dopo un reset, lo stesso
risultato lo si può ottenere con JP 0 oppure CALL 0.

Operazioni su blocchi di dati

Mnemonico     Tempo   Effetto sui flag    Operazione
                      C  Z  PV  S  N  H

LDI            16     -  -   #  -  0  0   (DE)=(HL)  DE=DE+1  HL=HL+1  BC=BC-1
LDD            16     -  -   #  -  0  0   (DE)=(HL)  DE=DE-1  HL=HL-1  BC=BC-1

LDIR           21 se BC>0    0  -  0  0   (DE)=(HL)  DE=DE+1  HL=HL+1  BC=BC-1
               16 se BC=0                 ripete e si arresta quando BC=0
LDDR           21 se BC>0    0  -  0  0   (DE)=(HL)  DE=DE-1  HL=HL-1  BC=BC-1
               16 se BC=0                 ripete e si arresta quando BC=0

CPI            16     -  #   #  #  1  #   A-(HL)   HL=HL+1  BC=BC-1
CPD            16     -  #   #  #  1  #   A-(HL)   HL=HL-1  BC=BC-1

CPIR           21     -  #   #  #  1  #   A-(HL)   HL=HL+1  BC=BC-1
               16  se A=(HL)              ripete e si arresta quando BC=0 OR A=(HL)
                   or BC=0
CPDR           21     -  #   #  #  1  #   A-(HL)   HL=HL-1  BC=BC-1
               16  se A=(HL)              ripete e si arresta quando BC=0 OR A=(HL)
                   or BC=0
Questo gruppo di istruzioni permette di spostare blocchi di byte
da un punto all'altro della memoria o di effettuare la ricerca di un
byte all'interno di un blocco di memoria. Per "blocco" si intende un
certo numero di byte contigui in un punto qualsiasi della memoria.

Tutte le istruzioni di spostamento LDI LDD LDIR LDDR usano il registro
HL come puntatore al blocco sorgente e il registro DE come puntatore al
blocco di destinazione, inoltre usano il registro BC come contatore a
16 bit.

L'istruzione LDIR in particolare rappresenta il sistema più veloce per
copiare da un punto all'altro della memoria un certo numero di byte:

           LD HL,indirizzo sorgente
           LD DE,indirizzo destinazione
           LD BC,numero di byte
           LDIR

Impostando DE un solo byte più avanti di HL è possibile ottenere il
riempimento di tutti i byte di un blocco di memoria con lo stesso valore,
il seguente esempio azzera i 300 byte a partire dall'indirizzo 50000:

           LD HL,50000
           LD (HL),0
           LD DE,50001
           LD BC,299
           LDIR

LDI funziona nello stesso modo ma non avviene la ripetizione automatica
di BC volte. LDD e LDDR sono equivalenti a LDI e LDIR ma la "direzione"
dei puntatori HL e DE è il decremento anziché l'incremento, in pratica
copiano i byte all'indietro rispetto al punto di partenza invece che
in avanti.

Le istruzioni di confronto confrontano l'accumulatore A con il valore
contenuto nella cella di memoria puntata dal registro HL, il risultato
del confronto è naturalmente segnalato dal flag di zero (il flag di
zero viene settato se la cella contiene lo stesso valore di A).

Anche CPI CPD CPIR CPDR incrementano o decrementano il puntatore (HL) e
decrementano il contatore BC. Le istruzioni CPIR e CPDR in particolare
ripetono i confronti al massimo BC volte. Queste istruzioni terminano
se viene trovata una cella il cui valore è uguale ad A, oppure se
BC raggiunge il valore zero.

Il massimo numero di byte spostabili è 65536 (impostando BC=0)

Scambi tra registri

Mnemonico     Tempo   Effetto sui flag    Operazione
                      C  Z  PV  S  N  H

EX AF,AF’       4     -  -   -  -  -  -   AF <-> AF’
EX DE,HL        4     -  -   -  -  -  -   DE <-> HL
EXX             4     -  -   -  -  -  -   BC<->BC’  DE<->DE’  HL<->HL’
Queste sono le uniche istruzioni di exchange (swap o scambio) tra
registri generali. EX AF,AF' e EXX coinvolgono il set alternativo
di registri. EX DE,HL scambia invece tra loro i valori di questi
due registri in modo molto veloce e senza ricorrere allo stack o
a un terzo registro di appoggio.

Bit, set e reset

Mnemonico     Tempo    Effetto sui flag     Operazione
                       C  Z  PV  S  N  H


SET b,r         8      -  -   -  -  -  -    bit b di r = 1
SET b,(HL)     15      -  -   -  -  -  -    bit b di (HL) = 1
SET b,(idx+dis)23      -  -   -  -  -  -    bit b di (idx+dix) = 1

RES b,r         8      -  -   -  -  -  -    bit b di r = 0
RES b,(HL)     15      -  -   -  -  -  -    bit b di (HL) = 0
RES b,(idx+dis)23      -  -   -  -  -  -    bit b di (idx+dix) = 0

BIT b,r         8      -  #   ?  ?  0  #    FlagZero = NOT( bit b di r         )
BIT b,(HL)     12      -  #   ?  ?  0  #    FlagZero = NOT( bit b di (HL)      )
BIT b,(idx+dis)20      -  #   ?  ?  0  #    FlagZero = NOT( bit b di (idx+dis) )
Queste istruzioni permettono di modificare e testare direttamente il
valore di un singolo bit. L'istruzione BIT effettua un test sul bit
specificato dell'operando, se il bit è a zero viene settato il flag
di zero.

L'esempio seguente mostra come testare il bit D5 di una cella di memoria
puntata da HL e saltare a un'altra perte del programma se questo bit è
a zero:

             LD HL,indirizzo cella
             BIT 5,(HL)
             JP Z,altro indirizzo
             ....istruzioni successive....

Gestione interrupt e CPU

Mnemonico     Tempo   Effetto sui flag    Operazione
                      C  Z  PV  S  N  H

IM 0            8     -  -   -  -  -  -   seleziona modo interrupt 0
IM 1            8     -  -   -  -  -  -   seleziona modo interrupt 1
IM 2            8     -  -   -  -  -  -   seleziona modo interrupt 2
EI              4     -  -   -  -  -  -   abilita interrupt INT (IFF=1)
DI              4     -  -   -  -  -  -   disabilita interrupt INT (IFF=0)
RETI           14     -  -   -  -  -  -   ritorno da interrupt INT
RETN           14     -  -   -  -  -  -   ritorno da interrupt NMI

LD A,I          9     -  - IFF2 -  0  0   A=I  
LD I,A          9     -  -   -  -  -  -   I=A

NOP             4     -  -   -  -  -  -   no operation
HALT            4     -  -   -  -  -  -   halt della CPU
Il registro I serve solo se si usa il modo interrupt 2,
in questo caso contiene la parte alta dell'indirizzo iniziale della
tabella dei 128 possibili vettori di interrupt gestibili con questa
modalità. Se non si usa l'IM2 il registro I può essere usato per
salvare il valore di A.

L'istruzione NOP non esegue alcuna funzione e può essere usata per
regolare con precisione i cicli di ritardo, su un sistema con clock
a 4 Mhz una NOP dura 1 microsecondo.

L'istruzione HALT ferma l'esecuzione del programma, la CPU non legge
più istruzioni dalla memoria e si "ritira" in uno stato isolato
eseguendo all'infinito delle NOP interne (continua però a rinfrescare
le eventuali RAM dinamiche).

Può uscire da questo stato solo con un reset o con l'arrivo di una
richiesta di interrupt. Quando la CPU è in HALT porta a zero il pin
HALT per segnalare all'esterno questa condizione.

Rotazioni e shift

Mnemonico     Tempo   Effetto sui flag    Operazione
                      C  Z  PV  S  N  H

RLA             4     #  -   -  -  0  0   
RL r            8     #  #   #  #  0  0
RL (HL)        15     #  #   #  #  0  0
RL (idx+dis)   23     #  #   #  #  0  0

RLCA            4     #  -   -  -  0  0   
RLC r           8     #  #   #  #  0  0
RLC (HL)       15     #  #   #  #  0  0
RLC (idx+dis)  23     #  #   #  #  0  0

RRA             4     #  -   -  -  0  0   
RR r            8     #  #   #  #  0  0
RR (HL)        15     #  #   #  #  0  0
RR (idx+dis)   23     #  #   #  #  0  0

RRCA            4     #  -   -  -  0  0   
RRC r           8     #  #   #  #  0  0
RRC (HL)       15     #  #   #  #  0  0
RRC (idx+dis)  23     #  #   #  #  0  0

SLA r           8     #  #   #  #  0  0   
SLA (HL)       15     #  #   #  #  0  0
SLA (idx+dis)  23     #  #   #  #  0  0

SRL r           8     #  #   #  #  0  0   
SRL (HL)       15     #  #   #  #  0  0
SRL (idx+dis)  23     #  #   #  #  0  0

SRA r          88     #  #   #  #  0  0   
SRA (HL)       15     #  #   #  #  0  0
SRA (idx+dis)  23     #  #   #  #  0  0

RLD            18     -  #   #  #  0  0   

RRD            18     -  #   #  #  0  0   
Nei disegni funzionali delle istruzioni di shift e rotazione
il quadrato contenente la lettera C indica il flag di carry,
il cui bit è infatti coinvolto da queste operazioni.

Le istruzioni RLA RLCA RRA E RRCA sono le versioni veloci
di RL A, RLC A, RR A e RRC A. RLCA ad esempio viene eseguita
in soli 4 cicli di clock contro gli 8 richiesti da RLC A,
e inoltre è lunga solo un byte contro i 2 di RLC A.

Le istruzioni RLD e RRD servono per effettuare degli shift
sui nibble di valori rappresentati in BCD e l'operazione
avviene spostando i nibble tra l'accumulatore e la cella
di memoria puntata da HL

Ingresso/uscita

Mnemonico     Tempo   Effetto sui flag    Operazione
                      C  Z  PV  S  N  H

IN r,(C)       12     -  #   #  #  0  #   A0..A7=C     r=D0..D7
IN A,(port)    11     -  -   -  -  -  -   A0..A7=port  A=D0..D7
OUT (C),r      12     -  -   -  -  -  -   A0..A7=C     D0..D7=r
OUT (port),A   11     -  -   -  -  -  -   A0..A7=port  D0..D7=A






INI            16     -  #   ?  ?  1  ?   A0..A7=C  (HL)=D0..D7  B=B-1  HL=HL+1
INIR           21 se B>0 1   ?  ?  1  ?   A0..A7=C  (HL)=D0..D7  B=B-1  HL=HL+1
               16 se B=0                  ripete e si arresta quando B=0

IND            16     -  #   ?  ?  1  ?   A0..A7=C  (HL)=D0..D7  B=B-1  HL=HL-1
INDR           21 se B>0 1   ?  ?  1  ?   A0..A7=C  (HL)=D0..D7  B=B-1  HL=HL-1
               16 se B=0                  ripete e si arresta quando B=0

OUTI           16     -  #   ?  ?  1  ?   A0..A7=C  D0..D7=(HL)  B=B-1  HL=HL+1
OTIR           21 se B>0 1   ?  ?  1  ?   A0..A7=C  D0..D7=(HL)  B=B-1  HL=HL+1
               16 se B=0                  ripete e si arresta quando B=0

OUTD           16     -  #   ?  ?  1  ?   A0..A7=C  D0..D7=(HL)  B=B-1  HL=HL-1
OTDR           21 se B>0 1   ?  ?  1  ?   A0..A7=C  D0..D7=(HL)  B=B-1  HL=HL-1
               16 se B=0                  ripete e si arresta quando B=0
Le istruzioni IN e OUT servono per ricevere o inviare un valore binario
sul BUS dati durante un accesso a periferica (o porta di ingresso uscita).
L'istruzione OUT (22),A invia sui bit A0..A7 del BUS indirizzi il valore
binario 22 e sui bit D0..D7 del BUS dati il valore binario contenuto in A.
L'istruzione IN A,(22) invia l'indirizzo su A0..A7 e poi riceve in A il
valore di D0..D7.

Le istruzioni dalla INI alla OTDR servono per l'accesso "a blocco"
alle porte di ingresso/uscita, sono le equivalenti delle "istruzioni
per blocchi di dati " specializzate però per l'accesso a periferiche.
L'istruzione INIR per esempio accede alla periferica il cui indirizzo
è contenuto nel regiatro C, legge un byte e lo memorizza nella cella
di memoria puntata da HL, dopo di che decrementa il registro B (usato
come contatore) e incrementa HL, a questo punto se B è maggiore di
zero l'istruzione viene ripetuta e così via. Il massimo numero di
cicli possibile con una singola istruzione è 256 (impostando B=0).

Altre istruzioni

Mnemonico     Tempo   Effetto sui flag    Operazione
                      C  Z  PV  S  N  H

SCF             4     1  -   -  -  0  0   Setta FlagCarry
CCF             4     #  -   -  -  0  ?   Inverte FlagCarry

NEG             8     #  #   V  #  1  #   A=0-A
CPL             4     -  -   -  -  1  1   A=NOT A

DAA             4     #  #   P  #  -  #   Aggiustamento decimale BCD

LD A,R          9     -  - IFF2 -  0  0   A=R
LD R,A          9     -  -   -  -  -  -   R=A

Le istruzioni SCF e CCF servono per settare e complementare il bit

del flag di carry. Non esiste un'istruzione diretta per resettarlo,
per fare questo si può comunque usare AND A, OR A, oppure la
coppia di istruzioni SCF e CCF in sequenza. 

NEG effettua il complemento a 2 dell'accumulatore. 

CPL inverte tutti i bit dell'accumulatore, è equivalente a
uno XOR 255. 

DAA serve per effettuare l'aggiustamento decimale dopo un'operazione
di somma o sottrazione tra valori espressi in BCD, in modo che i
nibbles non assumano valori maggiori di 9. Ad esempio, supponiamo
di avere in B il numero BCD 45 (0100 0101) e in A il numero BCD 18
(0001 1000). Una somma binaria effettuata con ADD A,B genera il
risultato 01000101+00011000=01011101. Il valore del nibble più
significativo è 0101 (5), quello del nibble meno significativo
è 1101 (13). Il 13 non è un valore ammesso in BCD e va corretto
effettuando una DAA dopo la somma. Si ottiene così il risultato
BCD corretto: 0110 (6) e 0011 (3), (45+18=63). Un eventuale riporto
sulla cifra più significativa viene memorizzato nel flag C e se ne
può tenere poi conto facendo una successiva ADC al posto di una ADD. 

Il registro R serve per generare l'indirizzo a 8 bit per il
rinfresco delle memorie dinamiche e si incrementa automaticamente
di uno ad ogni istruzione eseguita. Se il sistema non dispone di

memorie dinamiche questo registro può essere ignorato. Nota: solo i sette
bit meno significativi di R vengono incrementati, il bit più significativo
può essere scritto e riletto.

Istruzioni "non documentate"

idx_  = registri IXH IXL IYH IYL
Mnemonico     Tempo   Effetto sui flag    Operazione
                      C  Z  PV  S  N  H
ADC  A,idx_     8
ADD  A,idx_     8
SUB  idx_       8
SBC  A,idx_     8

AND  idx_       8
OR   idx_       8
XOR  idx_       8

CP   idx_       8

DEC  idx_       8

INC  idx_       8


LD   A,idx_     8
LD   B,idx_     8
LD   C,idx_     8
LD   D,idx_     8
LD   E,idx_     8

LD   idx_,A     8
LD   idx_,B     8
LD   idx_,C     8
LD   idx_,D     8
LD   idx_,E     8

LD   IXH,IXH    8
LD   IXH,IXL    8
LD   IXH,n     11
LD   IXL,IXH    8

LD   IXL,IXL    8
LD   IXL,n     11

LD   IYH,IYH    8

LD   IYH,IYL    8
LD   IYH,n     11
LD   IYL,IYH    8

LD   IYL,IYL    8
LD   IYL,n     11

SLL  (HL)      15
SLL  (idx+dis) 23
SLL  r          8


Pagina e disegni realizzati da Claudio Fin
Ultimo aggiornamento 23/8/2016