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 |
|