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