I salti

PIC18 - Salti

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.

Salto incondizionato

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:

gpto 0x00002

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.

Branch (diramazione) incondizionato

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

BRA

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

Branch condizionati

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.

bnz

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.

bnz

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

bc e bnc

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

Confronti

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

Le istruzioni di skip

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

Nota

  1. SI tratta anche di un esempio di come un commento possa indurre alla non comprensione del codice

 

Data di creazione di questa pagina: ottobre 2017
Ultima modifica di questa pagina: 12 aprile 2018


Licenza Creative Commons Attribuzione 4.0 Internazionale


Pagina principaleAccessibilitàNote legaliPosta elettronicaXHTML 1.0 StrictCSS 3

Vai in cima