L’Architettura del core M16C

Il core M16C di Renesas è certamente una buona proposta per il settore embedded poiché permette di sopperire alle diverse funzioni che il progettista software e hardware richiede per le proprie necessità: una struttura versatile e soprattutto una buona gestione degli interrupt. In modo particolare approfondiremo le caratteristiche dei registri, la sua mappa di memoria, il trattamento dei dati e la gestione degli eventi asincroni. La figura 1 mostra la proposta Renesas della famiglia M16C, come vediamo offre soluzioni basate a 8 bit fino a proposte più complesse.

Figura 1: architettura.

Figura 1: architettura.

In questo articolo analizzeremo in particolare la famiglia M16C/2x che copre le applicazioni fino a 16 bit. Il dispositivo  offre fino a 8 modi di indirizzamento e 91 istruzioni di base che si possono quindi utilizzare in 8 differenti possibilità. Inoltre, permette di sfruttare la possibilità del cosiddetto low power mode e consente di lavorare fino ad una frequenza di 24 Mhz: in questo modo l’istruzione più veloce è eseguita in circa 41.6 ns.

I registri

In figura 2 sono riportati i registri che offre il core M16C. Questi possono essere raggruppati nelle seguenti funzionalità:

➤ sei registri multifunzione ad uso generale. Questi registri, chiamati general purpose register, sono identificati con i mnemonici da R0 a R3, A0 e A1. Come viene evidenziato dalla figura, vediamo che è possibile utilizzare quattro di questi sei registri in diverse modalità da 8 bit, quindi quattro registri (R0 e R1), a 32 bit, due registri. In questa configurazione, solo due registri di questi sei sono utilizzati come registri a 16 bit. Nell’architettura M16C è possibile, selezionando un bit nel registro di stato (flag register), ottenere una configurazione chiamata shadow. Questi registri possono essere schematizzati nel seguente modo:

2 X 32-bit (R0R2, R1R3)

4 X 16-bit (R0, R1, R2, R3)

4 X 8-bit (R0L, R0H, R1L, R1H).

Figura 2: registri disponibili.

Figura 2: registri disponibili.

➤ Il componente  dispone, per gestire i vari modi di indirizzamento permessi, di uno stack base register (SB) e di un frames base (FB). Quest’ultimo registro è utilizzato, in special modo, per la gestione dei vari stack frames utilizzati nel linguaggio C. Il core è stato realizzato nell’ottica di minimizzare l’uso della memoria volatile (RAM): cosa assolutamente importante per i sistemi dedicati.

➤ Il core M16C utilizza un registro di stato per tenere traccia di tutte le possibili operazioni svolte: flag register (FLG). Un registro per la gestione della tabella dei vettori (INTB) degli interrupt: in questo modo è possibile posizionare in qualunque zona di memoria la tabella dei vettori. La figura 3 mostra il registro FLG con i suoi vari bit di stato.

Figura 3: flag register.

Figura 3: flag register.

➤ La presenza dei due stack pointer concludono poi l’offerta: user stack pointer (USP) e interrupt stack pointer (ISP). Come mostra la figura 4 esistono altri registri utilizzati per sfruttare le varie possibilità che il microprocessore  M16C offre, quale la gestione del DMA. Non solo, è possibile anche utilizzare i registri in maniera ottimizzata ricorrendo al loro scambio; infatti, questa architettura permette di selezionare, ricorrendo a un bit nel registro FLG, due diversi banchi chiamati 0 o 1 (a questo proposito si veda la figura 5). Una proposta del genere può, per esempio, essere utilizzata in una ISR per memorizzare  il contesto dei registri: in questo caso si ottimizza  il tempo speso nella ISR, poiché selezionando  il bit x in FLG si cambia il contesto al volo. Per questa ragione, alcuni compilatori basati su M16C devono essere in grado, magari ricorrendo ad uno switch durante la compilazione, di impartire una direttiva del genere.

Figura 4: i registri per m16c.

Figura 4: i registri per m16c.

 

Figura 5: cambio banco.

Figura 5: cambio banco.

La memoria

La gestione della memoria presente nel core M16C è differente tra i diversi modelli disponibili. È possibile, comunque, raggruppare in tre differenti modi di funzionamento: single-chip mode, memory-expansion mode e microprocessor mode. La cosa comune a queste tre differenti modalità è l’uso del registro SFR (Special Function Register), l’uso della memoria flash e RAM. Il registro SFR inizia dalla locazione 0, la RAM a 0x400. La memoria non volatile, flash, inizia dall’estremo limite superiore 0xFFFFF. Queste definizioni comuni per i dispositivi  della famiglia M16C permettono di utilizzare differenti dispositivi della stessa famiglia senza la necessità di dover riconsiderare  i limiti fisici della memoria.

➤ Single-chip mode. In questa configurazione sono utilizzate solo le risorse interne del componente. Questa modalità è selezionata attraverso  il pin CNVss (allo stato low al reset).

➤ Memory-expansion mode. Il passaggio in questa modalità è fatta, da single-chip mode, via software. In questa configurazione la memoria è definita come in figura 6.

Figura 6: modi di funzionamento.

Figura 6: modi di funzionamento.

➤ Microprocessor mode. In questa modalità il microprocessore utilizza la memoria interna del componente in aggiunta all’area esterna. Si accede in questa configurazione via hardware settando il pin CNVss in maniera appropriata (alto al reset).  I dati in memoria sono trattati secondo la convenzione Little-Endian e i componenti  M16C/2x e la serie 6x hanno la capacità di indirizzare uno spazio di indirizzamento di 20 bit. Il componente permette di spostare, a gruppi di byte, dati dalla memoria ad uno qualsiasi dei registri generali senza alterare il contenuto della parte restante. Infatti, con l’istruzione: MOV.B N,R0H si sposta un byte dalla memoria alla parte alta del registro R0 senza alterarne il byte meno significativo. Oppure, con MOV.W N,R0
In questo caso si spostano due byte dalla memoria al registro R0: il byte in posizione N è messo nella parte bassa del registro, mentre la porzione N+2 in quella alta (da b8 a b15). La tabella 1 mostra i consumi del componente in relazione agli stati operativi e alle tensioni di funzionamento.  I dati esposti rispecchiano quelli di un microcontrollore M16C/26, ma sono tipicamente paragonabili ai dispositivi con core M16C.

Tabella 1: consumi

Tabella 1: consumi

La gestione di una ISR e gli eventi asincroni

Gli eventi asincroni per la famiglia M16C si dividono in due categorie: interrupt hardware ed eventi software, la tabella 2 mostra questa suddivisione. Un interrupt software occorre quando il programma  esegue una particolare istruzione, ad esempio una BRK (Break Instruction) o INT (Software Interrupt Instruction): sono eventi che il progettista firmware vuole sollevare e gestire.

Tabella 2: interrupt su M16C

Tabella 2: interrupt su M16C

Esistono inoltre degli eventi che sono sollevati dal microprocessore quando si rileva un’operazione definita come division-by-zero o una situazione di overflow o se si tenta di eseguire un’istruzione non definita. Gli interrupt definiti come hardware sono divisi in due categorie: peripheral IO e Special. Gli interrupt definiti come Special non sono, di solito, associati ad azioni legate alle periferiche, ma identificano speciali prerogative che il core M16C fornisce. A titolo esemplificativo, possiamo raggruppare in questa famiglia gli interrupts del tipo DBC e di single-step che sono utilizzati per il debugging del codice e utilizzati per chi scrive strumenti di verifica. Viceversa, gli interrupt definiti come Peripheral IO identificano interrupt cui sono associate specifiche funzioni costruite attorno al core. L’architettura M16C fornisce un vettore indipendente per ogni periferica disponibile sul chip; in questo modo sono disponibili interrupt che gestiscono la ricezione e la trasmissione per le comunicazioni seriali, per esempio. In questo modo il core non implementa un dispatcher degli interrupt, ma ottimizza la gestione e il tempo di ogni ISR associata. La gestione di un interrupt in questa architettura coinvolge tre operazioni distinte che riguardano tre condizioni necessarie che devono verificarsi:

■  1-Il  bit interrupt request deve essere messo a 1. Ad ogni interrupt è associato un interrupt control register. L’utilizzo di questo registro è quello di fissare il livello dell’interrupt utilizzando i bit da 0 a 3, da ILVL0 a ILVL2, e l’interrupt request, bit 3, bit IR. E’ compito della CPU quello di fissare l’interrupt request: questo bit può essere solo letto e mai scritto dal software. In questo modo, quando un carattere è ricevuto da una periferica,  allora il bit di interrupt request dell’interrupt control della periferica è scritto dal suo blocco funzionale associato.

2-Il livello dell’interrupt corrente, del suo IPL, deve essere maggiore dell’interrupt priority level della CPU per garantirne la sua gestione. Questo specifico livello è impostato nel registro FLG della CPU, la priorità rispetta poi il suo valore numerico, in questo modo il livello 7 è l’interrupt con maggiore priorità e, viceversa, impostando un valore pari a zero si disabilitano questi eventi. Un segnale di reset forza a zero i bit IPL.

■  3-L’ultima considerazione da fare riguarda il bit I del registro FLG. Attraverso l’abilitazione di questo bit si abilitano, conseguentemente, gli interrupt del microprocessore. L’abilitazione riguarda tutti gli interrupt e non è legata, di conseguenza, ad un particolare segnale.

Quando un evento asincrono è rilevato dalla CPU e, successivamente, è correttamente riconosciuto,  allora il bit di interrupt request, per lo specifico interrupt, è azzerato dalla CPU. Il blocco funzionale della CPU che sovrintende alla gestione degli interrupt azzera il flag di interrupt enable prima di eseguire la routine ISR dell’utente per poi provvedere, successivamente,  alla sua riabilitazione al termine dell’ISR stessa. Inoltre, la CPU imposterà i valori dell’IPL pari ad un valore del livello corrente dell’interrupt sotto gestione. Anche in questo caso il valore originario sarà reinserito al termine della gestione.

Interrupt latency

Per i  sistemi embedded che utilizzano periferiche in modalità interrupt-driver questa caratteristica assume un aspetto importante. L’interrupt latency è il tempo speso dal microprocessore per gestire l’interrupt a meno dell’overhead dovuto alla routine stessa. E’ possibile dividere la sequenza di gestione dell’interrupt, insieme al tempo speso da parte del microprocessore, in quattro fasi.

1-La prima fase è variabile e dipende dall’istruzione corrente in esecuzione. Questo tempo può oscillare da 3 cicli macchina a 30 nel caso peggiore (esecuzione dell’istruzione DIVX). In pratica, non ci sarà il riconoscimento dell’interrupt fino a quando non sarà conclusa l’istruzione corrente: circa il 70% delle istruzioni del core M16C sono eseguite in un tempo pari, o inferiori, a 3 cicli macchina.

2-Il microprocessore impiega almeno 18 cicli nel caso di uno SP (stack pointer) a 16 bit e si può arrivare fino a 20 cicli nel caso di valori dispari dello SP e dell’indirizzo del vettore. Si computa anche il tempo speso per immagazzinare  il contesto corrente (program counter e il registro FLG). Una volta che queste informazioni sono salvate  il microprocessore esegue il  fetch dell’indirizzo della ISR dalla tabella dei vettori.

3-La terza parte è l’ISR vera e propria scritta dal programmatore.

■  4-Per concludere il ritorno dall’eccezione impiega 6 cicli. Questo è il tempo per chiudere l’interrupt e per rimetterenin esecuzione il programma precedentemente interrotto.

E’ sicuramente utile al progettista software conoscere l’esatta sequenza della procedura di interrupt. La prima cosa da sapere è che quando un interrupt occorre, riconosciuto dalla CPU, questa deve leggere l’indirizzo zero per determinare la ragione dell’evento e la sua priorità. Il programmatore, inoltre, non deve leggere o scrivere la locazione zero, una modifica accidentale dell’indirizzo zero provoca un comportamento anomalo della CPU. La CPU registra poi l’attuale contenuto del registro FLG in un’area interna e i flag I (Interrupt  Enable), D (Debug ), U (Stack Pointer Select) sono posti a zero. Non appena il flag di SP è azzerato questo provoca il cambio dello stack: nella routine di gestione dell’interrupt si utilizza l’ISP (Interrupt Stack Poiter). A questo punto i flag, che sono stati salvati in un’area interna, sono ora messi nel nuovo stack pointer al pari del program counter. A questo punto il bit associato all’interrupt request bit utilizzato per il riconoscimento dell’interrupt è posto a zero, mentre l’interrupt priority level nel registro FLG è modificato ad un valore pari a quello dell’interrupt sotto gestione. Esistono due casi particolari: un RESET forza l’IPL a 0, mentre le eccezioni WDT e NMI forzano il valore a 7. Finalmente, dopo questa sequenza svolta dal microprocessore, nel program counter si trova l’indirizzo della locazione  della ISR. Il core M16C ha due stack pointer e questa prerogativa con sente al microprocessore di gestire in maniera più efficiente sistemi multitasking; infatti, due stack eliminano la necessità di avere ridondanti interrupt space riservati in ogni stack di ciascun task.

 

 

 

 

Scarica subito una copia gratis

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend