FAST
REGISTER STACK
Un interessante meccanismo degli enhanced è il Fast
Register Stack.
Nei mid range, una chiamata da interrupt richiedeva la
classica introduzione con il salvataggio dei registri
principali e, all' uscita, il loro restore, risolto solitamente con due
macro.
;+++++
; PUSH/PULL save and restore W,PCLATH,STATUS and FSR registers -
; used on interrupt entry/exit
PUSH MACRO
movwf Saved_W ; save w reg
swapf STATUS,W ; affects NO status bits
clrf STATUS ; sets to BANK0
movwf Saved_Status ; save status reg
movf PCLATH,W
movwf Saved_Pclath ; save pclath
clrf PCLATH
movf FSR,W
movwf Saved_Fsr ; save fsr reg
ENDM
PULL MACRO
movf Saved_Fsr,W ; get saved fsr reg
movwf FSR ; restore
movf Saved_Pclath,W ; get saved pclath
movwf PCLATH
; restore
swapf Saved_Status,W ; get saved status in w
movwf STATUS
; restore status ( and bank )
swapf Saved_W,F ; reload into self to set status bits
swapf Saved_W,W ; and restore
ENDM |
E' chiaro che questa situazione
richiede un certo numero di registri per il salvataggio, oltre a consumare
spazio nella memoria programma e tempo nella sua esecuzione. Anche
qui gli enhanced risolvono brillantemente la situazione utilizzando
un gruppo di registri dedicati ed un meccanismo che, in modo
completamente automatico, provvede al salvataggio e al restore di WREG,
STATUS e PC. Questa possibilità viene attivata da programma
indicando un suffisso FAST all' istruzione di ritorno dall' interrupt,
che diventa:
retfie FAST ; rientro da interrupt e
restore dei registri E questa è l' unica
azione da effettuare, dato che i registri:
sono stati salvati al momento della chiamata dell' interrupt
in tre registri registri speciali, al di
fuori della memoria ordinaria e non altrimenti accessibili, chiamati WREGS, STATUSS e BSRS e da li vengono
prelevati e riposizionati al ritorno in modo totalmente automatico e
trasparente per il programmatore.
Solitamente, non occorrendo altro
per definire il contesto, questi tre elementi sono sufficienti.
Il vantaggio di questa opzione consiste nel fatto che non è
necessario implementare alcun salvataggio manuale dei registri, non vengono
utilizzati registri di RAM accessibile e non viene impegnato alcun tempo
supplementare per le operazioni di salvataggio e restore.
Questo sistema è utilizzabile anche per le chiamate a
subroutine, per cui si potrà avere un:
call subroutine, FAST
la cui chiusura, che
determina il restore automatico dei parametri salvati, è definito da :
return
FAST
Nel caso di un
interrupt, non occorre alcuna indicazione FAST, in quanto
il meccanismo provvederà ad avviarsi da se, mentre se voluto in una
subroutine deve essere esplicitata, altrimenti è assente.
NOTA:
Da questo deriva che
la parola FAST è riservata e non può essere altrimenti
usata. |
Se usato con
criterio, il sistema FAST del salvataggio del contesto è pratico e
potente, in quanto, oltre ad essere automatico, non richiede alcun tempo
supplementare per la sua esecuzione e neppure consuma memoria.
Se usato con criterio
in quanto esiste un solo livello di salvataggio che non sarà possibile
utilizzare contemporaneamente per una chiamata a subroutine e per una di
interrupt.
Ovvero, usando FAST intrinseco per la gestione dell' interrupt,
non sarà possibile usare il metodo in una chiamata a subroutine che abbia la
possibilità di sovrapporsi al tempo dell' interrupt stesso.
Inoltre, come
chiarito nella sezione dedicata agli interrupt, i PIC18 dispongono di due
livelli, di cui solo quello ad alta priorità potrà usare il
metodo FAST, in quanto, avendo la possibilità di sovra passare una chiamata a
bassa priorità, renderebbe inutile il salvataggio di ambiente di
quest'ultima, sovrascrivendo i registri.
In questi casi,
dovendo salvare il contesto, sarà necessario provvedere
"manualmente" con la solita sequenza di istruzioni ed usando i
registri disponibili in RAM.
Solitamente la
disponibilità di un solo livello per il salvataggio automatico del contesto
non crea grossi problemi, in quanto questa tecnica trova l' uso più intensivo
nella gestione di interrupt veloci, e quindi prioritari come livello,
piuttosto che nelle chiamate a subroutine.
AVVERTENZE:
-
A riguardo delle
subroutine, poi, occorre evidenziare che il metodo FAST è applicabile solo a
chiamate "lunge" effettuate dall' istruzione call
e non a chiamate corte a seguito di un rcall
.
Ovvero :
rcall
subroutinex , FAST
non è possibile e non sarà accettata dall' assemblatore.
-
Così pure non ha senso un retlw
FAST , dato che una cosa del genere cercherebbe di recuperare
un ipotetico registro W salvato , mentre intende ritornare nello stesso tempo
con un determinato valore in W !
- La procedura di salvataggio nel Fast Register Stack è comandata
dal suffisso FAST nel caso della CALL, ma è automatica nel
caso dell' interrupt. Ovvero, alla chiamata da interrupt i
registri sono salvati in ogni caso, anche se poi non saranno poi
recuperati con il RETFIE FAST.
- Esiste un solo
gruppo di registri dedicati a questa operazione, per cui
potranno essere utilizzati solamente da una procedura per volta.
Se due procedure chiamano FAST in sequenza, i dati dell' ultima
chiamante sovrascriveranno quelli precedenti, che andranno persi.
Le conseguenze
dei punti 2 e 3 sono
queste:
- se si sta utilizzando FAST nelle CALL, l' area di salvataggio
potrà essere utilizzata da una sola CALL per volta
- se si sta utilizzando
l' interrupt, FAST per le CALL è possibile, ma assolutamente
sconsigliabile, onde
evitare sovrascritture
- se si stanno
utilizzando interrupt con priorità, si dovrà riservare il metodo
FAST per l' interrupt a priorità alta e ricorrere ad un
salvataggio manuale per l' ambiente dell' interrupt a bassa
priorità (dato che un interrupt HP può interrompere un LP e
quindi cancellarne i dati del Fast Register Stack).
- FAST salva
solamente WREG, STATUS e BSR. Se devono essere salvati anche
altri registri, ad esempio gli FSR, occorrerà aggiungere una
gestione manuale per questi.
|
Dunque è evidente che il FAST è pensato dai progettisti principalmente per
il servizio di interrupt ad alta priorità, ma , come bonus ulteriore, viene
reso disponibile anche per le chiamate a subroutine.
I riassunto, la
situazione è la seguente :
-
non si utilizzano
interrupt: il metodo FAST può essere applicato senza problemi alle
chiamate a subroutine
-
si impiegano
interrupt ad un solo livello: in questo caso si
utilizzerà il metodo FAST per la gestione dell' interrupt e, dove
necessario, si salverà il contesto alle chiamate di subroutine con i
classici mov
-
si impiegano
tutti e due i livelli di interrupt: in questo caso il FAST sarà
riservato alle chiamate a priorità alta, mentre per quelle a bassa
priorità ed eventualmente per le subroutine si provvederà
"manualmente"
Una tipica sequenza
di salvataggio "manuale" del contesto può essere la seguente:
ISR
:
; save context
movwf wSave, 0
movff STATUS, statSave
movff BSR, bsrSave
movff FSR0L, fsr0lSave
movff FSR0H, fsr0hSave
...
...
;gestione interrupt
...
...
; restore context
movff fsr0lSave, FSR0L
movff fsr0hSave, FSR0H
movff bsrSave, BSR
movf wSave, w, 0
movff statSave, STATUS
retfie
|
Se non si utilizza la sintassi FAST, il sistema di accesso e
ritorno all' interrupt è lo stesso dei mid range e il salvataggio dei
registri è completamente a carico del programmatore.
|