I programmi difficilmente sono costituiti da una semplice sequenza di istruzioni da eseguire una dopo l'altra: in genere sono presenti cicli o diramazioni, cioè esecuzione non sequenziale di istruzioni.
L'indirizzo dell'istruzione che verrà eseguite è contenuta nel program counter (PC). Esso potrà:
Inoltre il salto può essere fatto sempre (salto incondizionato) oppure solo al manifestarsi di determinate condizioni, tipicamente il valore di un flag.
Le istruzioni di salto incondizionato permette di eseguire una istruzione posta in una qualunque cella della memoria programma, saltando in avanti o indietro all'interno del programma. Il nuovo indirizzo da porre nel PC può essere scritto direttamente nel codice come numero oppure, cosa assolutamente preferibile, fatta calcolare automaticamente all'assemblatore attraverso l'uso di una label.
Esempio 1 - Il codice seguente esegue infinite volte l'incremento unitario del registro WREG che passa dal valore iniziale 0 a 255 per poi tornare a 0 per ricominciare nuovamente:
clrf WREG
ripeti incf WREG
goto ripeti
Il programma, una volta caricato nella memoria flash, appare nel seguente modo:
Si noti in particolare come l'istruzione goto ripeti sia stata assemblata come goto 0x2. Questo numero è costituito da 21 bit:
0x2 è l'indirizzo a cui si trova l'istruzione incf WREG e la label ripeti.
Esercizio 1 - Eseguire il codice dell'esempio 1 passo-passo, osservando il valore del registro WREG
Si confronti tale codice con quanto già mostrato in questo esempio, praticamente identico, e al contenuto dei fogli tecnici.
Questa istruzione, a partire dal nome, è molto simile alla precedente. Essa somma (o sottrae) al valore del Program Counter un numero compreso tra -1024 e 1023, permettendo al programma di andare avanti (o indietro) saltando fino ad un massimo di circa 1000 istruzioni rispetto all'istruzione stessa di bra.
A volte questo tipo di salto è indicato come salto relativo, mentre il goto è indicato come salto assoluto.
Esempio 2 - Il codice seguente fa, apparentemente, l'identica cosa dell'esempio 1:
clrf WREG
ripeti incf WREG
bra ripeti
Il codice salvato in memoria è invece diverso (e più compatto):
Facciamo riferimento al foglio tecnico e vediamo come è stato costruto:
Costruiamo a mano il codice operativo 0xD7FE (1101 0111 1111 1110) dell'istruzione bra ripeti, mostrato nell'immagine:
Per fortuna è stato calcolato automaticamente dall'assemblatore...
Esercizio 2 - Eseguire il codice dell'esempio 2 passo-passo, osservando il valore del registro WREG
I salti condizionati permettono di eseguire un'istruzione piuttosto che un'altra a seconda del valore di uno dei flag. Sono alla base dei costrutti che ad alto livello vengono indicati come if-then-else oppure cicli while-do e for.
Per il test possono essere utilizzati i flag N, Z, C e OV, producendo 8 diverse istruzioni di salto (bn, bnn, bz, bnz, bc, bnc bov e bnov) a seconda se il salto debba avvenire quando flag vale zero oppure vale uno. Per la descrizione, peraltro implicita nel nome, si rimanda ai fogli tecnici e agli esempi di seguito riportati.
Questa istruzione esegue un salto in funzione del valore del flag Z.
Esempio 3 - Si consideri il seguente codice che fa riferimento al flag Z e all'istruzione bnz (branch if not zero):
movlw 0x10 ; Il numero 0x10
viene memorizzato in WREG
ripeti
decf WREG ; WREG viene decrementato di 1
bnz ripeti ; Se il risultato non è zero, torna indietro alla label
ripeti
sleep ; Il programma termina
Il funzionamento è intuitivo, anche grazie ai commenti, ma è importante leggere sui fogli tecnici i dettagli. In particolare è necessario prestare attenzione al fatto che il salto avviene o meno in corrispondenza del valore di un flag (nel caso specifico del flag ZERO) e non in funzione del contenuto di un registro.
Molto simile a bnz, l'istruzione bz (Branch if Zero), ovviamente dal funzionamento esattamente contrario.
Due osservazioni:
Esempio 3b
ricomincia ; ATTENZIONE: questo codice non funziona come
sembra!
movlw 0x10
incf WREG
movlw 0 ; Azzero WREG
bnz ricomincia ; Se WREG non è zero, ricomincia
sleep
Esercizio 3 - Eseguire il codice degli esempi 3 e 3b passo-passo, osservando il valore del flag Z
Esempio 4 - Il codice seguente utilizza il flag C (carry) per eseguire un codice molto simile al precedente:
movlw 0xF0
ancora
incf WREG
bnc ancora
finito
sleep
Esercizio 4 - Eseguire il codice passo-passo, osservando il valore del flag Z e del flag C
Per eseguire il confronto tra una variabile ed un numero (o un'altra variabile) occorre eseguire due istruzioni:
Esempio 5: Il seguente codice confronta il contenuto del registro W con il numero 0x10 ed esegue alcune istruzioni se sono uguali oppure altre se sono diversi.
Con una sintassi simil-C: if (WREG == 0x10) then ... else ...
movlw 0x30 ; Modificare il numero da mettere in
WREG
sublw 0x10 ; 0x10 - (WREG) -> WREG; WREG == 0x10 ?
bz uguali
diversi ; Label non necessaria, solo per chiarezza
nop ; Inserire qui le istruzioni da eseguire se WREG != 0x10
nop
bra finito
uguali
nop ; Inserire qui le istruzioni da eseguire se WREG == 0x10
nop
finito
sleep
Esercizio 5 - Eseguire passo-passo il codice mostrato modificando la prima riga ed inserendo in WREG un numero maggiore, minore o uguale a 0x10
Esempio 6 - Il seguente codice confronta il contenuto del registro W con il numero 0x10 ed esegue alcune istruzioni se WREG è maggiore di 0x10 oppure altre se minore o uguale.
Con una sintassi simil-C: if (WREG > 0x10) then ... else ...
movlw 0x30 ; Modificare il numero da mettere in
WREG
sublw 0x10 ; 0x10 - (WREG) -> WREG; WREG == 0x10 ?
bc minore
maggiore ; Label non necessaria, solo per chiarezza
nop ; Inserire qui le istruzioni da eseguire se WREG > 0x10
nop
bra finito
minore
nop ; Inserire qui le istruzioni da eseguire se WREG <= 0x10
nop
finito
sleep
Esercizio 6 - Eseguire passo-passo il codice dell'esempio 6 modificando la prima riga ed inserendo in WREG un numero maggiore, minore o uguale a 0x10
Esercizio 6a - Modificare il codice (ed eventualmente i commenti e i nomi delle label) usando bnc
Esercizio 6b - Scrivere il codice che si comporta come il codice simil-C: if (WREG >= 0x10) then ... else ...
Un salto condizionato può essere anche ottenuto con diverse istruzioni di skip, traducibile come salta l'istruzione successiva. Spesso il codice prodotto è più intuitivo
Esempio 7 - Decrementare WREG fino a 0, partendo da un valore qualunque (0x10 nel codice mostrato)
movlw 0x10
ripeti
decfsz WREG ; decrementa WREG e salta l'istruzione seguente (bra sleep)
se WREG == 0
bra ripeti
sleep
Esercizio 7 - Riscrivere gli esempi precedenti a partire dal 3 usando le varie istruzioni di skip
Data di creazione di questa pagina: ottobre 2017
Ultima modifica di questa pagina: 12 aprile 2018
Assembly PIC18 - Versione 0.5 - aprile 2018
Copyright 2016-2018, Vincenzo Villa (https://www.vincenzov.net)
Assembly PIC18 di Vincenzo Villa è distribuito con Licenza Creative Commons Attribuzione 4.0 Internazionale