BTFSC reg,b | Skip se bit b di (reg) = 0 | |
BTFSS reg,b | Skip se bit b di (reg) = 1 | |
INCFSZ reg,d | d = (reg) + 1 Skip se d = 0 | |
DECFSZ reg,d | d = (reg) - 1 Skip se d = 0 | |
GOTO addr | Salto all'indirizzo addr | |
CALL addr | Chiamata di subroutine | |
RETURN | Ritorno da subroutine | |
RETLW n | Ritorno da subr.con valore in W | |
RETFIE | Ritorno da interrupt |
E ora eccoci ad un insieme
corposo e importante di istruzioni e concetti. Fino ad adesso infatti
abbiamo visto solo quali sono i modi per impostare e manipolare
in modo elementare i
nostri dati, scriverne il valore su 8 LED e stop. Se fosse
tutto qui un micro servirebbe a ben poco, ciò che manca ancora
sono delle istruzioni in grado di far prendere delle decisioni
al programma,
in modo da effettuare un'operazione o un'altra a seconda del verificarsi di una
certa condizione, ed eventualmente ripetere più volte un gruppo di
istruzioni, in modo da creare così un processo dinamico che può
continuare a leggere gli ingressi e generare gli opportuni segnali
sulle uscite.
Le istruzioni di questo gruppo si
dicono di controllo flusso
in quanto permettono effettivamente di
alterare il normale flusso lineare di esecuzione, creando delle
ramificazioni
(branch, salti) a punti (indirizzi) diversi del
programma. Usando i salti è possibile strutturare
il programma
a piacimento (il significato di struttura diverrà più chiaro andando
avanti), a tale proposito è utile però ricordare che uno stile
di programmazione corretto (che facilita il progetto, la lettura e la
manutenzione) prevede l'uso di tre soli tipi fondamentali di
struttura
, ciascuna con un solo punto di inizio e una sola fine:
La struttura sequenziale è
quanto abbiamo già visto fino ad ora, è un insieme (o blocco) di
istruzioni da eseguire una dopo l'altra. La struttura condizionale
prevede la possibilità di porsi una domanda (contenuta nel rombo) a cui
si può rispondere con un si o con un no, e di eseguire istruzioni (o
blocchi di istruzioni) differenti a seconda dei due casi. La terza
struttura permette di ripetere una o più istruzioni finchè la
risposta alla domanda vale si (oppure no a seconda delle necessità).
Con questa simbologia grafica è possibile rappresentare il
funzionamento di un qualsiasi programma sotto forma di flowchart
(diagramma di flusso). Ciascun rettangolo può essere
un'istruzione elementare, oppure contenere più istruzioni o anche
sottostrutture
. Uno
dei rettangoli dell'istruzione condizionale può cioè contenere al suo
interno altre strutture condizionali e/o iterative, che a loro volta ne
possono contenere delle altre... il livello di dettaglio che si vuole
rappresentare dipende dalle necessità caso per caso.
Ma vediamo allora come un
programma può porsi una domanda grazie alle prime due istruzioni della
tabella: BTFSS e BTFSC. Queste servono a
testare
(o controllare) il valore (stato logico 1 o 0) di un
qualsiasi bit di un
qualsiasi registro, e permettono di saltare (skip) l'esecuzione
dell'istruzione successiva se il bit testato si trova nello stato
previsto. La prima salta l'istruzione seguente se il bit testato è 1
(alto, set), la seconda se è 0 (basso, clear). Il bit da testare è
specificato con il parametro b,
e come sempre può andare da 0 per indicare il bit meno significativo,
a 7 per quello più significativo.
Come si vede in questi due esempi viene testato il flag Z, in fondo i flags sono due bit come tutti gli altri, e diventa evidente la loro grandissima importanza. Infatti è anche grazie al loro valore (che dipende dal risultato delle istruzioni appena eseguite) che il programma può prendere decisioni anche complesse e comportarsi in modi diversi a seconda delle circostanze.
Un semplice skip dell'istruzione
successiva non fornisce però ancora la flessibilità necessaria per
realizzare una completa struttura condizionale equivalente all' IF THEN
ELSE (se, allora altrimenti) dei linguaggi ad alto livello
. Questa si
ottiene con l'aggiunta dell'istruzione GOTO (vai a,
salta), che permette di saltare ad un punto qualsiasi del programma da
un qualsiasi altro punto. Quando una GOTO è usata insieme ad una
istruzione di skip si crea un salto condizionato. E'
naturalmente possibile mettere una GOTO in qualsiasi punto del
programma, in tal caso questo salto prende il nome di salto incondizionato.
E' buona norma però ridurre il più possibile l'utilizzo dei salti perché
rendono complicata la lettura e la
manutenzione/correzione del programma. Il loro utilizzo andrebbe
limitato (se possibile) esclusivamente per la creazione
delle
strutture fondamentali condizionale e iterativa. Per indicare il punto di arrivo
di un salto (GOTO) si usano normalmente delle etichette (label), cioè dei
nomi inizianti nella prima colonna del testo. E' evidente che in un programma
non devono mai esserci due label uguali, in quanto ciascuna identifica un
indirizzo della memoria programma ben preciso.
L'esempio seguente mostra come realizzare in assembly la struttura IF THEN ELSE completa. Nell'esempio viene testato il bit 0 del registro DIREZ, se vale 0 viene eseguita l'istruzione RLF LUCE,F (saltando la GOTO ELSE) seguita dal salto a ENDIF, altrimenti viene eseguita l'istruzione RRF LUCE,F. Le istruzioni da eseguire in un caso o nell'altro possono essere anche più di una, a differenza della skip semplice che al massimo permette di saltare l'esecuzione di una singola istruzione.
L' esempio seguente presenta la struttura iterativa, ed è molto importante comprenderlo appieno perché su questo genere di struttura/funzionamento si basa gran parte dell'elaborazione nei casi reali.
E' una generica sezione di programma in cui ad un certo
punto si carica il valore 4 in un registro della RAM (chiamato
come al solito PIPPO). Seguono poi delle istruzioni indicate con
dei puntini. Ed infine troviamo altre 4 istruzioni. Le prime due
servono a sottrarre 1 dal registro PIPPO. La terza controlla il valore
del flag Z che viene settato quando il risultato
dell'istruzione precedente vale 0. Se il flag Z è settato viene
saltata l'istruzione seguente e il programma prosegue. Altrimenti, se
PIPPO dopo la sottrazione non vale 0 e il flag Z non è settato, lo
skip non viene effettuato, perciò viene eseguita la GOTO che rimanda
indietro al punto indicato dall'etichetta NEXT. In pratica si crea
quello che viene chiamato un
loop (ciclo, anello) che ripete il blocco di istruzioni interne
esattamente 4 volte. Il registro PIPPO funziona da
contatore di ciclo. Siccome il suo valore parte da 4 e decrementa ad
ogni ciclo, al quarto passaggio raggiunge lo 0 e il loop termina, il
programma prosegue cioè con le istruzioni successive....
MOVLW 4 ;W=4 MOVWF PIPPO ;PIPPO=W NEXT .... .... MOVLW 1 ;W=1 SUBWF PIPPO,F ;PIPPO=PIPPO-W BTFSS STATUS,Z ;SE PIPPO=0 ALLORA SKIP (FINE CICLO) GOTO NEXT ;ALTRIMENTI TORNA A NEXT
Abbiamo ormai quasi tutti gli elementi per
poter finalmente animare
un pò i nostri LED, prima però vediamo
qualche altra istruzione. La terza e la quarta istruzione della tabella
sono istruzioni potenti
, in quanto permettono in un colpo
solo di incrementare o decrementare di 1 un registro, ed effettuare
automaticamente uno skip dell'istruzione seguente se il risultato
dell'operazione vale 0. L'esempio precedente può perciò essere
riscritto più succintamente nel seguente modo:
MOVLW 4 ;W=4 MOVWF PIPPO ;PIPPO=W NEXT .... .... DECFSZ PIPPO,F ;DECR.PIPPO, SE=0 ALLORA SKIP (FINE CICLO) GOTO NEXT ;ALTRIMENTI TORNA A NEXT
Con i salti (condizionati e non) è già possibile creare qualsiasi
flusso elaborativo, tuttavia se c'è bisogno di creare
delle suddivisioni
logiche tra sezioni di programma che eseguono compiti specifici,
oppure ci sono gruppi di istruzioni ripetuti frequentemente in diversi
punti del programma, è preferibile ricorrere alle subroutines (o
sottoprogrammi). Ogni subroutine può essere così considerata come un
modulo
a parte, da chiamare
quando serve il suo
servizio. Le subroutines sono semplicemente porzioni di programma che
vengono chiamate con l'istruzione CALL (nello stesso modo di GOTO) ma
terminano con l'istruzione
RETURN che fa ritornare il programma all'istruzione successiva alla
CALL di partenza. Questo comportamento è possibile perché ad ogni
CALL il PIC salva il contatore di programma (il program
counter, che tiene conto dell'indirizzo dell'istruzione in esecuzione)
in un'area speciale chiamata stack, e lo riprende quando incontra una
RETURN. Il PIC 16F628 ha un'area di stack a 8 livelli,
è quindi possibile chiamare fino a 8 subroutines una dentro l'altra
(nidificate o nested). L'uso delle subroutines è
estremamente consigliato, in quanto sono l'unica cosa in grado di
tenere in ordine
un programma complesso spezzandolo in più moduli,
cioè porzioni di codice di dimensioni ridotte che eseguono ciascuna un
compito ben specifico, più facile da comprendere e da mettere a punto.
Un'altra buona ragione per l' utilizzo dei sottoprogrammi è che
all'evenienza possono essere copiati in altri
programmi per essere riutilizzati. In gergo una raccolta utile di
subroutines riutilizzabili si chiama libreria
.
Ci sono altre due forme di istruzione di ritorno da subroutine, la RETLW e la RETFIE. La prima permette il ritorno da una subroutine con un valore specifico caricato nell'accumulatore, come vedremo serve per creare delle tabelle dati nell'area programma, cosa altrimenti impossibile in quanto questa memoria non è accessibile dalle comuni istruzioni che lavorano solo sui registri dalla memoria dati. La RETFIE invece si usa nel caso in cui la subroutine da terminare sia un gestore di interrupt.
Esperimento:effetto supercar, cioè deve accendersi un LED alla volta scorrendo da destra verso sinistra per poi tornare indietro e così via.
Dapprima definiamo le variabili di lavoro (registri) che ci occorrono.
Un registro di nome LUCE conterrà il valore a 8 bit da scrivere sulla
porta di uscita, uno chiamato DIREZ conterrà 0 o 1 a seconda che la direzione
di scorrimento voluta sia verso sinistra o verso destra, ed infine due
registri di nome L_CONT e H_CONT serviranno come contatore di ciclo a
16 bit per una subroutine di ritardo. Quest'ultima è necessaria
perché la velocità di esecuzione sarebbe altrimenti
così rapida da non poter essere notata, in pratica tutti i LED
apparirebbero ugualmente illuminati a causa della persistenza
dell'immagine sulla nostra retina. Visto che ogni istruzione impiega un
certo tempo per essere eseguita è evidente che eseguendo decine di
migliaia di volte poche istruzioni all'interno di un loop si possono
ottenere ritardi di tempo considerevoli. E' necessario usare 16 bit
per il conteggio in quanto usandone solo 8 il massimo ritardo
ottenibile sarebbe troppo breve (meno di 2 millisecondi). Per
visualizzare un effetto gradevole ci occorre invece un ritardo di
diverse decine di ms. Una soluzione poteva essere quella di richiamare
la sbroutine di ritardo a 8
bit della durata di 2 ms molte volte di fila, ma questo avrebbe in
ogni caso comportato l'uso di un altro ciclo e di un altro registro di
conteggio. In questo esempio invece si usano due byte in modo tale da
considerarli come un unico registro a 16 bit, con cui realizzare cicli
da 1 a 65536 ripetizioni, ed è il primo esempio di creazione
via
software di un tipo di dato che può assumere valori maggiori di quelli
trattabili direttamente dal micro. Un valore a 16 bit è composto
infatti da due byte detti alto (H, più significativo) e basso (L, meno
significativo). Il valore contenuto in quello alto ha peso 256, una
unità nel byte alto vale cioè 256 volte la stessa unità nel byte
basso, questo vuol dire che il valore complessivo a 16 bit di due byte
H ed L è dato da H*256 + L. Nel nostro caso impostiamo un ciclo di
5320 ripetizioni, la parte alta varrà 20 e quella bassa 200 (infatti
20*256+200=5320). Per decrementare un valore a 16 bit si decrementa
prima la parte bassa, se si ha un rollover negativo (da 0 si torna a
255) allora si decrementa anche la parte alta. Quando entrambe le parti
contengono zero (basta fare un OR tra di loro e verificare se si setta
il flag Z) il ciclo termina. Durante l'esecuzione del programma il
valore binario iniziale 00000001 di LUCE viene spostato verso sinistra
di una posizione alla volta tramite l'istruzione RLF. L'azzeramento del
flag C prima della
rotazione fa si che da destra non entri mai un altro bit a 1. Quando il
bit a 1 contenuto in LUCE raggiunge la posizione 7 (cioè l'ottava a
sinistra, la piùsignificativa) il valore del registro direzione viene
messo a 1, in modo tale da abilitare lo spostamento verso destra. Allo
stesso modo quando il bit a 1 di LUCE ritorna nella posizione 0
il valore della direzione cambia di nuovo riabilitando lo spostamento
verso sinistra come all'inizio. Il programma è senza fine
perché il GOTO finale rimanda all'infinito alla posizione MAINLOOP,
in totale occupa 33 locazioni di memoria programma
delle 2048 disponibili, e utilizza 4 byte di memoria RAM dei 224
disponibili.
;----------------------------------------------------- ; Programma effetto supercar ;----------------------------------------------------- PROCESSOR 16F628 RADIX DEC INCLUDE "P16F628.INC" __CONFIG 11110100010000B ;----------------------------------------------------- LUCE EQU 32 H_CONT EQU 33 L_CONT EQU 34 DIREZ EQU 35 ;----------------------------------------------------- ORG 0 BSF STATUS,RP0 ;Attiva banco 1 CLRF TRISB ;Rende PORTB un'uscita BCF STATUS,RP0 ;Ritorna al banco 0 MOVLW 00000001B MOVWF LUCE ;LUCE=00000001 CLRF DIREZ ;DIREZ=0 MAINLOOP MOVF LUCE,W MOVWF PORTB ;Scrive LUCE sulla PORTB BCF STATUS,C ;Azzera flag C BTFSC DIREZ,0 ;Se DIREZ=0 (sinistra) skip GOTO LAB1 ;altrimenti GOTO LAB1 RLF LUCE,F ;Ruota LUCE verso sinistra GOTO LAB2 ;GOTO fine struttura IF LAB1 RRF LUCE,F ;Ruota LUCE verso destra LAB2 BTFSC LUCE,7 ;Se bit 7 di LUCE è 0 skip INCF DIREZ,F ;altrimenti direzione=destra BTFSC LUCE,0 ;Se bit 0 di luce è 0 skip CLRF DIREZ ;altrimenti direzione=sinistra CALL DELAY ;Richiama subroutine di ritardo GOTO MAINLOOP ;Nuovo ciclo del programma ;----------------------------------------------------- DELAY MOVLW 20 ;Carica 5320 nei 16 bit MOVWF H_CONT ;formati dai due byte MOVLW 200 ;H_CONT e L_CONT MOVWF L_CONT DELAY2 DECF L_CONT,F ;Decrementa parte bassa del contatore COMF L_CONT,W ;Inverte i bit BTFSC STATUS,Z ;Se tutti zero c'è stato rollover DECF H_CONT,F ;allora decrementa parte alta MOVF L_CONT,W ;Carica in W la parte bassa IORWF H_CONT,W ;Mettila in OR con la parte alta BTFSS STATUS,Z ;Se tutto zero skip (fine ciclo) GOTO DELAY2 ;Altrimenti ritorna a DELAY2 RETURN ;----------------------------------------------------- END
Qui sotto sono riportati i flowchart completi della sezione principale del programma (chiamata anche main) e della subroutine delay. A fianco del disegno sono riportate le istruzioni che compongono le varie parti. Come si può vedere la chiamata alla subroutine si rappresenta con un rettangolo con aggiunte due righe laterali.
Il programma è completo e funzionante, tuttavia è possibile una piccola ottimizzazione della struttura IF THEN ELSE. Infatti nel caso cui vi sia una sola istruzione da eseguire sotto il THEN e una sola sotto l'ELSE la struttura può essere scritta in modo più compatto risparmiando una istruzione e la necessità di dover definire due etichette a cui saltare, da così:
BTFSC DIREZ,0 GOTO LAB1 RLF LUCE,F GOTO LAB2 LAB1 RRF LUCE,F LAB2 ......a così:
BTFSC DIREZ,0 RRF LUCE,F BTFSS DIREZ,0 RLF LUCE,FIl main del nostro programma supercar diventerebbe cioè:
BSF STATUS,RP0 ;Attiva banco 1 CLRF TRISB ;Rende PORTB un'uscita BCF STATUS,RP0 ;Ritorna al banco 0 MOVLW 00000001B MOVWF LUCE ;LUCE=00000001 CLRF DIREZ ;DIREZ=0 MAINLOOP MOVF LUCE,W MOVWF PORTB ;Scrive LUCE sulla PORTB BCF STATUS,C ;Azzera flag C BTFSC DIREZ,0 ;Se DIREZ=0 (sinistra) skip RRF LUCE,F ;Ruota LUCE verso destra BTFSS DIREZ,0 ;Se DIREZ=1 (destra) skip RLF LUCE,F ;Ruota LUCE verso sinistra BTFSC LUCE,7 ;Se bit 7 di LUCE è 0 skip INCF DIREZ,F ;altrimenti direzione=destra BTFSC LUCE,0 ;Se bit 0 di luce è 0 skip CLRF DIREZ ;altrimenti direzione=sinistra CALL DELAY ;Richiama subroutine di ritardo GOTO MAINLOOP ;Nuovo ciclo del programma
Lo stesso sistema può essere usato per spostare
o meglio copiare
un singolo bit di un qualsiasi registro in un altro bit di un qualsiasi
altro registro. Nell'esempio seguente copiamo il valore del flag C nel
bit 4 del registro PIPPO:
BTFSC STATUS,C BSF PIPPO,4 BTFSS STATUS,C BCF PIPPO,4
La sequenza appena vista va bene anche per trasferire il valore di un singolo bit della RAM su un singolo pin di uscita di una porta. Se si lavora invece solo con registri in memoria, come in questo questo caso specifico, è possibile in realtà una ulteriore riduzione di istruzioni. Basta impostare inizialmente il bit di PIPPO ad un valore specifico, per esempio 0, e poi cambiandolo subito dopo SOLO SE il flag C è settato:
BCF PIPPO,4 BTFSC STATUS,C BSF PIPPO,4
Per concludere va ricordato che tutte le istruzioni viste in precedenza duravano sempre un ciclo macchina. Le istruzioni viste in questo capitolo invece possono durare anche 2 cicli macchina. Per la precisione le istruzioni di salto, chiamata e ritorno (GOTO, CALL, RETURN, RETLW, RETFIE) richiedono sempre 2 cicli macchina, mentre gli skip ne richiedono 2 solo se la condizione è verificata.
CLRWDT | Azzera watch dog timer | |
SLEEP | Standby mode | |
NOP | Nessuna operazione |
Per completare la lista delle 35 istruzioni eseguibili dai PIC mancano le tre qui sopra. La prima serve per azzerare il contatore WDT, un registro hardware che incrementa automaticamente e, se abilitato, produce un reset del PIC quando arriva all'overflow (rollover). Questo serve in applicazioni critiche in cui è necessario che il PIC riparta automaticamente in caso di blocco accidentale del programma (crash) per esempio a causa di un forte disturbo elettrico. Nel caso in cui il WDT sia abilitato, nel programma si dovrà periodicamente effettuare un CLRWDT prima che il tempo scada.
La seconda manda in sleep il micro, che sospende ogni attività ed entra in modalità risparmio di energia. Per uscire dalla condizione di sleep il micro va resettato oppure deve ricevere una richiesta di interrupt nel caso in cui gli interrupt siano stati abilitati.
Della tabella rimane ancora la curiosa istruzione NOP. Come indicato nella descrizione questa istruzione non esegue nessuna funzione. E' una follia dei progettisti? Niente affatto, ogni microprocessore dispone di una istruzione NOP, che serve fondamentalmente per far passare del tempo in modo controllato senza influire su alcun altro registro. Come ogni altra istruzione anche una NOP richiede un ciclo macchina per essere eseguita, a 4 MHz un ciclo macchina dura 1 uS, pertanto l'inserzione di una NOP in un punto qualsiasi del programma determina un ritardo di 1 uS tra la fine dell'istruzione precedente e l'inizio di quella successiva. Ora, 1 uS di ritardo è poca cosa, se però una o più NOP vengono racchiuse in un ciclo che le esegue centinaia o migliaia di volte si possono ottenere ritardi precisi di qualsiasi durata.
E con questo la lista delle operazioni elementari è terminata, ora si
tratta solo di vedere molti esempi su come possono essere combinate
assieme per realizzare i compiti più disparati. Chi conosce già
l'assembly di altri tipi di microprocessore noterà la mancanza di
alcune cose, come un comodo stack su cui salvare i propri
registri di lavoro, o l' assenza di registri indice
che permettono
l'accesso alle celle della ram puntandole da programma con un indirizzo
contenuto in un altro registro. In realtà quest'ultima possibilità c'è, ma,
come per altre cose in un microcontroller, la sua potenza è ridotta. E'
un'operazione comunque possibile che è bene conoscere perché molto
importante.
I PIC dispongono di un registro di nome FSR che funziona da indirect
memory data pointer
. Un valore scritto in questo registro viene
considerato come un indirizzo della RAM. Per scrivere o leggere a
questo indirizzo così puntato
da FSR basta scrivere o leggere nel
registro INDF. Un esempio chiarisce meglio il concetto:
MOVLW 32 MOVWF FSR ;Punta la cella di indirizzo 32 MOVLW 255 MOVWF INDF ;Ci scrive 255 MOVLW 32 MOVWF FSR ;Punta la cella di indirizzo 32 MOVF INDF,W ;Legge in W il suo contenuto
Siccome il valore caricato in FSR può
anche essere incrementato o decrementato, è possibile gestire una
certa sezione della RAM come un array, cioè una lista di byte
raggiungibili con un indice progressivo senza la necessità di doverne
definire un nome come si fa solitamente con gli altri registri. Un'area
del genere può servire per memorizzare ad esempio dei numeri battuti
su una tastiera o dei valori in arrivo da una porta seriale. Una
sezione di memoria usata in questo modo viene anche chiamata buffer
.
Il codice seguente azzera 10 byte a partire dall'indirizzo RAM 40 (usa
il registro PIPPO come contatore di ciclo):
MOVLW 40 MOVWF FSR ;Punta la cella di indirizzo 40 MOVLW 10 MOVWF PIPPO ;Carica 10 in PIPPO NEXT CLRF INDF ;Azzera la cella RAM puntata da FSR INCF FSR,F ;Incrementa il puntatore DECFSZ PIPPO,F ;Se fatti 10 cicli termina GOTO NEXT ;altrimenti torna a next
Opcode operando | Cyc. | Flags | Descrizione |
ADDWF reg,d | 1 | Z C | d= W + (reg) |
ADDLW n | 1 | Z C | W = W + n |
ANDWF reg,d | 1 | Z | d = W AND (reg) |
ANDLW n | 1 | Z | W = W AND n |
BCF reg,b | 1 | Bit b di (reg) = 0 | |
BSF reg,b | 1 | Bit b di (reg) = 1 | |
BTFSC reg,b | 1(2) | Skip se bit b di (reg) = 0 | |
BTFSS reg,b | 1(2) | Skip se bit b di (reg) = 1 | |
CALL addr | 2 | Chiamata di subroutine | |
CLRF reg | 1 | Z=1 | (reg) = 0 |
CLRW | 1 | Z=1 | W = 0 |
CLRWDT | 1 | Azzera watch dog timer | |
COMF reg,d | 1 | Z | d = NOT (reg) |
DECF reg,d | 1 | Z | d = (reg) - 1 |
DECFSZ reg,d | 1(2) | d = (reg) - 1 Skip se d = 0 | |
GOTO addr | 2 | Salto all'indirizzo addr | |
INCF reg,d | 1 | Z | d = (reg) + 1 |
INCFSZ reg,d | 1(2) | d = (reg) + 1 Skip se d = 0 | |
IORLW n | 1 | Z | W = W OR n |
IORWF reg,d | 1 | Z | d = W OR (reg) |
MOVF reg,d | 1 | Z | d = (reg) |
MOVLW n | 1 | W = n | |
MOVWF reg | 1 | (reg) = W | |
NOP | 1 | Nessuna operazione | |
RETFIE | 2 | Ritorno da interrupt | |
RETLW n | 2 | |
Ritorno da subr. con valore in W |
RETURN | 2 | Ritorno da subroutine | |
RLF reg,d | 1 | C | d = rlf (reg) |
RRF reg,d | 1 | C | d = rrf (reg) |
SLEEP | 1 | Standby mode | |
SUBLW n | 1 | Z C | W = n - W |
SUBWF reg,d | 1 | Z C | d = (reg) - W |
SWAPF reg,d | 1 | d = swap (reg) | |
XORLW n | 1 | Z | W = W XOR n |
XORWF reg,d | 1 | Z | d = W XOR (reg) |