dal 2015 - visita n. 2356
StruttureControllo
StruttureControllo

 

Le strutture di controllo ASM


Introduciamo adesso alcune strutture fondamentali della programmazione utili in tantissime situazioni. In ogni programma, degno di tale nome, capita spesso di dover ripetere le stesse operazioni (un lavoro elementare) per un certo numero di volte. Un ciclo (loop) è una struttura di controllo di un programma che esegue per molte volte lo stesso insieme di istruzioni. Si dice anche che il ciclo è una struttura iterativa.

In un ciclo si possono distinguere quattro fasi: inizializzazione, lavoro, aggiornamento e controllo.

  1. Con l'inizializzazione si effettua la fase di preparazione del ciclo, nella quale si fa in modo che il lavoro venga eseguito correttamente per la prima volta.
  2. Il lavoro è l'insieme delle istruzioni che devono essere eseguite tante volte (in modo iterativo).
  3. La fase di aggiornamento prepara la struttura ad eseguire il lavoro per un'altra volta.
  4. La fase di controllo, o test, serve per valutare se si deve eseguire un'altra iterazione del ciclo o se è giunto il momento di smettere (uscita dal ciclo).

Esistono due possibilità di base per impostare correttamente un ciclo, entrambe fanno riferimento alla posizione del modulo di controllo rispetto agli altri moduli. Le figure indicano le due situazioni tipiche: con controllo in testa (prima di cominciare il blocco di lavoro), o con controllo in coda (dopo aver eseguito il lavoro per la prima volta).


Nei diagrammi delle figure si vede facilmente come il programma giri dentro al ciclo (parte rossa) fino a che la condizione di controllo non lo fa uscire (parte verde). Un giro di un ciclo è ciò che si intende con il termine iterazione.

I puristi indicano molti motivi per utilizzare cicli con controllo in testa (sicurezza, integrità, etc.), ma programmando in Assembly x86 questa indicazione viene spesso disattesa, perché il programma risulta di lettura più semplice se il controllo è in coda ed anche perché l'istruzione specifica per realizzare i cicli (LOOP) usa un controllo in coda. In ogni caso sarà poi l'esperienza a guidare il programmatore nella scelta migliore a seconda delle situazioni.

Di norma si conosce a priori il numero di iterazioni, ma non è sempre così. Come primo esempio supponiamo di voler eseguire 7 volte un certo lavoro e troviamo delle soluzioni intuitive che sfruttano i 2 diagrammi visti in precedenza. In questo tipo di cicli nell'inizializzazione si deve impostare un contatore, CX, che terrà traccia in ogni istante del numero di giri che sono stati compiuti. Chiameremo questo contatore "contatore di controllo". La fase di aggiornamento modifica il contatore per segnalare che è stata eseguita un'altra iterazione. Il test stabilisce se il ciclo è stato percorso il giusto numero di volte e se è giunto il momento di uscirne.


Vediamo ora la realizzazione in Assembly dei due cicli illustrati dai diagrammi di flusso.


         .....
         mov   cx,1   ;Inizial. 
 iteraz: cmp   cx,7
         ja    uscita
         .....
         .....        ;Lavoro
         .....
         inc   cx
         jmp   iteraz
 uscita: .....        
ciclo con logica di controllo in testa

         .....
         mov   cx,1   ;Inizial. 
 iteraz: .....
         .....        ;Lavoro
         .....
         inc   cx
         cmp   cx,7
         ja    uscita
         jmp   iteraz
 uscita: .....        
ciclo con logica di controllo in coda

Dopo aver esaminato i due casi classici, vediamo come sia possibile arrivare ad una soluzione ottimizzata con l'uso di vari accorgimenti. Il modo più efficiente per fare i cicli in Assembly utilizza un contatore a decremento ed un controllo in coda.

prima versione

         .....
         mov   cx,7   ;Inizial. 
 iteraz: .....
         .....        ;Lavoro
         dec   cx
         jnz   iteraz
 uscita: .....        
seconda versione

         .....
         mov   cx,7   ;Inizial. 
 iteraz: .....
         .....        ;Lavoro
         loop  iteraz
 uscita: .....        

ciclo a decremento
con logica di controllo in coda

Nella prima versione, come si vede, manca la cmp finale che non è più necessaria perché il ciclo, andando a rovescio, finisce sempre con lo zero e la condizione di zero viene rilevata direttamente dalla dec. Con questa versione si risparmia una cmp per ogni iterazione del ciclo. Il risparmio di un'istruzione può sembrare un'inezia, ma diventa significativo se fatto in cicli che si ripetono per centinaia/migliaia di volte, come accade per esempio in moduli che fanno parte del sistema operativo o di applicazioni grafiche.

Nella seconda versione è stata utilizzata l'istruzione "loop  iteraz" che semplifica ulteriormente la scrittura del ciclo in quanto raggruppa la "dec  cx" e la "jnz  iteraz". E' importante notare che l'istruzione LOOP presuppone l'uso esclusivo del registro CX con funzione di contatore. Anche se non è esplicito nella scrittura dell'istruzione il registro CX viene sempre decrementato dalla LOOP. Ogni volta che stiamo per usare una LOOP dobbiamo chiederci cosa c'è attualmente in CX e se quello che c'è è il valore giusto per il contatore del ciclo, altrimenti i risultati possono essere imprevedibili. L'uso della loop rende certamente più compatto il codice anche se con l'evoluzione delle CPU x86, dal 486 in avanti, il risultato non è più veloce delle altre istruzioni equivalenti.



Asm86
Panoramica 8086
Istruzioni JMP
Macro Tastiera
Macro Video Testo
Macro Video Grafica
Macro Mouse
Macro File
Codici ASCII
Codici Scansione
Macro Time
Macro Memoria
Macro Video VESA
Strutture di Controllo
Elementi Bistabili
Mappe di Bit
Strutture Dati



Volere e potere sono le due coordinate di ogni azione umana.
Paul Valéry

Valid CSS!
pagina generata in 0.001 secondi