T&T - PIC

 

Equivalente Assembly dello statement Case

 


La scelta tra più alternative

Capita sovente di dover implementare del codice che consenta la selezione tra più alternative. Più in generale, all' uscita di una certa procedura si avrà a disposizione un indice a 8 bit e quindi si potranno definire fino a 256 possibili alternative per puntare diverse operazioni nel programma. 
Occorre verificare con una comparazione a quale scelta corrisponde l' indice. 

In C la funzione è svolta dal case:

switch(input)
{
case 1:
funct1();
break;
case 2:
funct2();
break;
case 3: 
....
case n:
break;
default: 
cout<<"Input error";
}

In Assembly una via è quella di utilizzare una lookup table che contenga tante linee quante sono le scelte possibili; questa è adeguata in ogni caso, ma, se il numero delle scelte alternative non è particolarmente grande, si può usare una tecnica diversa, che consiste nella semplice comparazione dell' indice con le possibilità di scelta.

I set di istruzioni dei PIC consente diverse tecniche di comparazione, ad esempio utilizzando operazioni di sottrazione o somma e verificando subito dopo lo stato dei flag C, N, o Z.

Se consideriamo l' istruzione di sottrazione, ad esempio nella forma:

subwf  file, w

possiamo osservare che alcuni bit dello STATUS vengono modificati a seconda del risultato dell' operazione.  Se consideriamo il flag Z -  zero, esso è settato quando il risultato dell' operazione è zero. 

             MOVF   switch, W     ; muovere l' indice in W 
      SUBWF  index1, W     ; Sottrarre 'W' (=indice) dallo switch 
      BTFSC  STATUS, Z     ; Se Z=0 saltare prossima istruzione
       GOTO  case1         ; se Z=1 saltare all' esecuzione del case
      GOTO   non_equal     ; altrimenti procedere

Alcuni microcontroller, inoltre, hanno istruzioni dirette per il confronto, come la CPFSEQ degli Enhanced.

La cosa è, ovviamente, valida anche se le scelte sono literal, come solitamente capita:

              MOVF   switch, W     ; muovere l' indice in W 
      SUBWF  index1, W     ; Sottrarre 'W' (=indice) dallo switch 

      BTFSC  STATUS, Z     ; Se Z=0 saltare prossima istruzione
       GOTO  case1         ; se Z=1 saltare all' esecuzione del case
      GOTO   non_equal     ; altrimenti procedere

Se dobbiamo, però, ripetere la comparazione per più elementi, è preferibile ricorre ad un' altra via, quella dell' istruzione di OR esclusivo, la XORWF.


XOR o OR esclusivo: un breve ripasso.

La funzione di OR esclusivo o XOR (eXclusive OR) origina questa tavola della verità:

input B input A A OR B A XOR B
0 0 0 0
0 1 1 1
1 0 1 1
1 1 1 0

In pratica, XOR rende 1 se i due bit confrontati sono diversi e 0 se sono uguali.

Le sue proprietà sono queste:

Operazione Proprietà Descrizione
A^B = B^A commutativa cambiando ordine agli operatori il risultato non cambia
A^B^C = A^ (B^C)=(A^B)^C associativa operando un raggruppamento, il risultato non cambia
A^A = 0 non idempotenza XOR con se stesso dà risultato 0
A^!A=1 complementazione XOR con l' inverso di se stesso dà risultato 1
A^0 = A identità XOR con 0 non cambia l'operando
A ^ 1 = !A inversione XOR con 1 inverte l' operando

Possiamo utilizzare questa istruzione come operatore in una comparazione.


XOR per comparare

Se vogliamo verificare che un dato sia uguale ad un altro, ecco che, per quanto appena detto, l' operazione di XOR è ideale. Infatti, se due valori sono uguali, si tratta di un caso di A^A il cui risultato è 0. Se non fosse zero, questo indicherebbe che i due valori sono in  qualche modo diversi.

Dunque, per verificare se W contiene un certo valore, basterà:

  MOVF    val_to_compare,W    ; valore da comparare in W
  XORLW   index               ; valore con cui comparare      
  BTFSC   STATUS, Z           ; check flag Z   
   GOTO   equal               ; se =1 sono uguali
  GOTO    not_equal           ; se no sono diversi

Questo ci consente di effettuare con semplicità una scelta tra diversi possibili valori. Ad esempio, vogliamo verificare l' uguaglianza di un determinato valore con una lista di possibilità.

       MOVF    val_to_compare,W
   XORLW   index1
   BTFSC   STATUS, Z  
    GOTO   case1
  
MOVF    val_to_compare,W
   XORLW  
index2
   BTFSC   STATUS, Z  
    GOTO   case2
   .....
  
MOVF    val_to_compare,W
   XORLW  
indexn
   BTFSC   STATUS, Z  
    GOTO   casen   
   GOTO    not_equal

La riga MOVF val_to_compare,W viene ripetuta ad ogni comparazione dato che l'operazione XORLW distrugge il contenuto di W.

Per i PIC18F possiamo utilizzare l' istruzione BZ :

       MOVF    val_to_compare,W
   XORLW   index1
   BZ      case1
   MOVF    val_to_compare,W
   XORLW   index2
   BZ      case2
   .....
   MOVF    val_to_compare,W
   XORLW   indexn
   BZ      casen
   GOTO    not_equal

ma questa scrittura è adeguata a tutti i PIC utilizzando una semplice macro:

 BZ    MACRO    dest
   BTFSC   STATUS, Z  
    GOTO   dest
       ENDM   

Possiamo implementare una ulteriore variazione migliorativa considerando le proprietà dell' XOR e in particolare la sequenza

A^B^B = A^ (B^B) = A^0 = A

Quindi

   MOVF    val_to_compare,W
   XORLW   index1
   XORLW   index1

rende  W = val_to_compare . Di conseguenza possiamo scrivere:

   MOVF    val_to_compare,W
   XORLW   index1
   BZ      case1
   XORLW   index1^index2
   BZ      case2
   XORLW   index2^index3
   BZ      case3
   .....
   MOVF    val_to_compare,W
   XORLW   index-1 ^ index
   BZ      casen
   GOTO    not_equal

In questo modo sarà possibile comparare un valore a 8 bit con una serie di indici ed eseguire una diversa operazione a seconda del loro valore.
Questo non è certamente il solo modo per effettuare una serie di scelte, però, nel caso di un limitato numero di comparazioni, è senz'altro il più semplice ed efficace. 


Argomenti collegati:


 

Copyright © afg. Tutti i diritti riservati.
Aggiornato il 07/04/13.