Normalmente il firmware realizzato per una scheda embedded contiene sia i driver di basso livello per la gestione delle periferiche hardware, sia il programma applicativo. Questa soluzione non sempre è vantaggiosa: chi sviluppa il firmware deve conoscere i dettagli dell’ hardware della scheda ed avere le competenze necessarie per lo sviluppo dell’applicativo.
Una soluzione più generale consiste nel separare il firmware di basso livello, che dipende dall’hardware utilizzato, dal programma applicativo. La scheda, in questo caso, verrà fornita con un rudimentale bios che metterà a disposizione le funzioni a cui dovrà fare riferimento il programmatore dell’applicativo per accedere alle varie periferiche della scheda. La realizzazione di due diversi firmware indipendenti comporta però alcuni problemi tra cui la necessità di creare e gestire una tabella dei vettori interrupt modificabile dall’applicativo. Solitamente la tabella dei vettori di interrupt è statica e viene definita in fase di programmazione del firmware.
Separando il firmware bios dall’applicativo, quest’ultimo non può modificare la tabella statica degli interrupt contenuta in memoria Rom o Flash ma dovrà necessariamente utilizzare una copia contenuta in memoria Ram: la RIT (Ram Interrupt Table). La RIT memorizza i puntatori al punto di ingresso delle diverse procedure di interrupt, le sue dimensioni dipendono dal numero di interrupt presenti nel micrcontrollore. Utilizzando la RIT i vettori di interrupt possono essere modificati in qualsiasi momento secondo le esigenze dell’applicativo. Ad esempio il firmware bios potrà associare una procedura di interrupt alla periferica di comunicazione seriale per consentire la programmazione in circuit della scheda, mentre l’applicativo potrà successivamente sostituire questo vettore con la propria procedura di comunicazione. Si deve però risolvere il seguente problema: il micro, quando riconosce un determinato segnale di interrupt, ricava dalla tabella statica dei vettori l’indirizzo della procedura di interrupt da eseguire, ma in questo caso l’informazione è memorizzata in Ram nella RIT. Il firmware bios perciò deve definire una procedura di interrupt generica da eseguire ad ogni interrupt per ricavare le informazioni dalla RIT ed eseguire la procedura corretta. Una possibile soluzione per microcontrollori 8051 è la seguente: Poiché nella tabella statica dell’8051 ogni vettore di interrupt ha a disposizione 8 byte il firmware bios memorizza per ogni interrupt il seguente codice
push DPL
mov DPL,Low (RITADDR+isroffs)
sjmp ISRvect
Dove RITADDR è l’indirizzo della memoria RAM in cui inizia la tabella RIT e isroffs è l’offset del vettore di interrupt all’interno della tabella RIT, offset che ovviamente cambia per ogni interrupt. La procedura ISRvect è la procedura generica di interrupt definita all’interno del firmware bios. (Listato 1).
;——————; push DPH ; DPL saved at isr call push B ; push ACC ; push PSW ; ; return addr à stack mov A,#LOW (ISREnd) push ACC mov A,#HIGH(ISREnd) push ACC ; isr vector addr à stack ; DPL set at isr call mov DPH,#HIGH(RITADDR) movx A,@DPTR push ACC inc DPTR movx A,@DPTR push ACC ret ; jmp to isr vect ISREnd: ;———-———; pop PSW ; pop ACC ; pop B ; pop DPH ; pop DPL ; reti
Listato 1 |
La procedura salva I registri principali del micro e aggiunge sullo stack due indirizzi: l’indirizzo della procedura di uscita dall’interrupt (ISREnd) che ripristina il contesto salvato, e l’indirizzo prelevato dalla RIT che corrisponde al punto d’ingresso della procedura di interrupt. Per accedere alla RIT si utilizza il registro DPTR: gli 8bit meno significativi del registro (DPL) sono definiti dal singolo vettore di interrupt mentre gli 8 bit più significativi (DPH) sono comuni a tutti gli interrupt. La procedura ISRvect termina con l’istruzione ret che scarica dallo stack l’ultimo indirizzo caricato e pertanto esegue la procedura di interrupt definita dall’applicativo. Quando questa procedura termina ed esegue a sua volta l’istruzione ret, scarica dallo stack l’indirizzo della procedura ISREnd che, dopo aver ripristinato il contesto iniziale termina l’interrupt corrente. Il prezzo da pagare per questa flessibilità è una risposta più lenta all’interrupt poiché per accedere alla procedura associata si deve eseguire anche il codice di gestione della RIT.