Personal computer/Mapping

Wikibooks, manuali e libri di testo liberi.
Indice del libro

Nei capitoli precedenti abbiamo definito le caratteristiche logiche di CPU, sistema di memoria ed interfacce di Input/Output, in questo capitolo vedremo come collegare chip di memoria ed interfacce ad una CPU con parallelismo 8 bit.

Il progetto di elaboratore elettronico è basato sulla CPU 8088, se ne osserverà il pin-out e ci si concentrerà sulle caratteristiche logiche e sulle temporizzazioni dei segnali in ingresso alla CPU, in particolare il segnale di ready comandato dall'integrato 8284.

Per il sottosistema di memoria si vedrà il funzionamento di EPROM e RAM.

Per le interfacce se ne osserverà una generica, con considerazioni del tutto indipendenti dal reale dispositivo periferico controllato, per poi passare allo studio di interfacce di comunicazione standard quali una porta seriale COM (Interfaccia 8250 gestita tramite il protocollo RS 232) ed una porta parallela (8259).

Per la maggiore semplicità si considerano le interfacce gestite da programma (gestione a polling), tuttavia verrà preso in considerazione un integrato (PIC 8259) per la gestione delle interfacce tramite interruzioni (gestione a interrupt).


Caratteristiche e funzionamento degli integrati notevoli[modifica]

Decodifica degli indirizzi[modifica]

Qualsiasi dispositivo fisico, che sia una memoria o una interfaccia, per essere accessibile dal software deve poter essere indirizzato, ovvero deve occupare una finestra dello spazio di indirizzamento.

Il mapping consiste nell'associare ad un dispositivo una porzione dello spazio di indirizzamento e di generare, a partire dai bit sul bus degli indirizzi e dai segnali di comando, un segnale di selezione per quel dispositivo.

Sia un'interfaccia che una memoria, ma vale lo stesso discorso per qualsiasi agente master indirizzabile (controller DMA, controller hard disk, ...), occupa n=2^k posizioni nello spazio di indirizzamento. n rappresenta il numero di oggetti (ad esempio un registro) di 8 bit indirizzabili, k il numero di bit di indirizzo per il dispositivo.

Avendo a disposizione k indirizzi, che si traducono in k connessioni, qualsiasi dispositivo ha al suo interno un decoder di k variabili con un ingresso di enable detto chip select o chip enable che consente alla CPU di abilitare soltanto il dispositivo selezionato.

Quasi sempre il mapping dei dispositivi è allineato, ovvero l'indirizzo più basso tra tutti quelli associati al dispositivo è un multiplo della dimensione in byte dello stesso. L'allineamento semplifica notevolmente la decodifica degli indirizzi. Supponiamo infatti di avere un dispositivo con A indirizzi mappato in uno spazio di indirizzamento da 2^a bit (a bit di indirizzo), posto i = A - a esistono 2^i posizioni in cui poter mappare il dispositivo, tuttavia soltanto se questo è allineato gli a indirizzi dello spazio di indirizzamento possono essere considerati come il concatenamento di A e i. Supponendo di avere uno spazio di indirizzamento di 10 bit e voler mappare un dispositivo da 256 byte = 2^8. Allineando il dispositivo i due bit più significativi dello spazio di indirizzamento indicano che sono possibili 4 finestre (2^2) che sono appunto i byte da 0-255, 256-511, 512-767, 768-1024. Osservando la configurazione binaria degli indirizzi le quattro finestre sono (in parentesi l'indirizzo esadecimale)

  00 0000 0000  ( 0 00H )
  00 1111 1111  ( 0 FFH )
  
  01 0000 0000  ( 1 00H )
  01 1111 1111  ( 1 FFH )
  
  10 0000 0000  ( 2 00H )
  10 1111 1111  ( 2 FFH )
  
  11 0000 0000  ( 3 00H )
  11 1111 1111  ( 3 FFH )

Gli 8 bit meno significativi saranno decodificati internamente al dispositivo per selezionare il relativo elemento di memoria, i due bit più significativi serviranno invece per selezionare il dispositivo in una delle quattro finestre.

Sono possibili due tipi di decodifica degli indirizzi:

  • decodifica completa
  • decodifica semplificata

Decodifica completa[modifica]

Le decodifica completa è effettuata utilizzando tutti i bit di offset dell'indirizzo, i bit più significativi che non vengono utilizzati dal dispositivo per decodificare internamente una cella di memoria. Nell'esempio precedente di bus indirizzi a 10 bit e elemento di memoria a 8 bit, la decodifica completa è effettuata decodificando i 2 bit più significativi dell'indirizzo.

La decodifica più semplice è calcolare per ogni dispositivo il mintermine corrispondente allo spazio occupato, posto, ad esempio, che l'elemento di memoria sia nella parte più bassa dello spazio di indirizzamento ( 0-255 byte) allora i due bit più significativi dell'indirizzo valgono 0. Il chip select del dispositivo sarà, in logica positiva, CS = A9 * A8 realizzabile con un AND.

È possibile anche una decodifica con decoder 2:4 che presenta in uscita tutte le possibili finestre allineate. L'uscita del decoder corrispondente alla porzione di spazio di indirizzamento in cui è mappato il dispositivo è collegata con il suo ingresso chip select.

L'elemento più usato per la decodifica degli indirizzi è la PAL, una rete logica ad i ingressi e o uscite, identificata da iLo (ad esempio 10L8), che permette di generare o chip select a partire da i bit di ingresso. La PAL è una rete programmabile tramite espressioni in logica positiva ma le uscite sono già negate, per cui direttamente collegabili al CS* dei dispositivi. La scelta di una PAL si dimostra conveniente soprattutto quando i bit di selezione sono molti, per realizzare la stessa funzione di una PAL 10L8 sarebbe necessario un decoder a 10 ingressi e quindi a 1024 uscite.

Decodifica semplificata[modifica]

La decodifica semplificata o parziale viene effettuata eliminando alcuni bit dall'espressione dei chip select dei dispositivi mappati, mantenendo il corretto funzionamento del sistema.

Se considero un sistema con indirizzi a 10 bit e due elementi di memoria da 256 celle ciascuno ( 8 bit ) mappate in questo modo

  0 00H
  0 FFH  -> chip1
  
  1 00H
  1 FFH  -> chip2
  
  2 00H
  2 FFH
  
  3 00H
  3 FFH

I segnali dei chip select in logica positiva sono

 CSchip1 = !A9 * !A8
 CSchip2 = !A9 *  A8

Le due espressioni dei chip select individuano univocamente una finestra di 256 byte all'interno dello spazio di indirizzamento, che tuttavia presenta degli spazi liberi (la metà alta). Si può quindi pensare di eliminare l'univocità delle finestre selezionate mantenendo la separazione delle finestre.

Ad esempio eliminando il bit A9 dell'espressione del chip select si ottiene

 CSchip1 = !A8
 CSchip2 =  A8

che indirizzano le seguenti finestre

  0 00H
  0 FFH  <- CSchip1
  
  1 00H
  1 FFH  <- CSchip2
  
  2 00H
  2 FFH  <- CSchip1
  
  3 00H
  3 FFH  <- CSchip2

Ogni segnale di chip select individua due finestre nello spazio di indirizzamento, ognuna da 256 byte. Con queste espressioni dei chip select il chip1 risulta mappato in due finestre, così come il chip2 ma non essendoci sovrapposizione tra i chip select dei due dispositivi questa codifica semplificata risulta corretta.

Mentre da un lato con la decodifica parziale si ottengono delle espressioni semplificate per i chip select (nell'esempio un solo bit piuttosto che due), dall'altro si ha un forte spreco delle risorse. Eliminando n bit dall'espressione dei chip select ogni dispositivo va ad occupare 2^n posizioni.

Gestione delle interfacce tramite programma[modifica]

Una generica interfaccia ha dei registri interni che possono essere buffer dati (ingresso/uscita), registri di stato, di controllo, e che devono essere mappati nello spazio di I/O ed accessibili dalla CPU.

Ipotizziamo le seguenti associazioni

  Buffer Ingresso registro all'indirizzo 80H
  Buffer Uscita registro all'indirizzo 81H
  Status registro all'indirizzo 82H
  Control registro all'indirizzo 83H
  Control Word dato binario che è necessario scrivere nel registro di controllo per assicurare il corretto 
                     funzionamento dell'interfaccia, valore D4H

Il programma per prima cosa dovrà inizializzare l'interfaccia

  BufferIn          EQU 80H                  ; l'istruzione EQU definisce degli identificatori
  BufferOut         EQU 81H                  ;  associati a delle costanti
  StatusRegister    EQU 82H
  ControlRegister   EQU 83H
  ControlWord       EQU D4H
                    MOV AL, ControlWord      ; carica in AL la costante ControlWord
                    OUT ControlRegister, AL  ; e trasferiscila nel registro associato a ControlRegister

Una volta inizializzata l'interfaccia sono possibili le operazioni di

Lettura dello stato

  IN AL, StatusRegister    ; carica in AL il contenuto del registro di stato dell'interfaccia

Lettura di un dato, Input

  IN AL, BufferIn          ; Preleva dal Buffer il contenuto del registro
  MOV Dati[SI], AL         ; memorizzane il valore nel vettore Dati all'indirizzo SI
  INC SI                   ; incrementa l'indice del vettore per poter prelevare un altro dato dal buffer

Scrittura di un dato, Output

  MOV AL, Dati[SI]         ; Copia il valore della cella del vettore da trasferire
  OUT BufferOut, AL        ; memorizzala nel registro Buffer Out
  INC SI                   ; incrementa l'indice del vettore per poter trasferire un altro dato del vettore

Le operazioni di lettura e scrittura necessitano una sincronizzazione, l'interfaccia deve comunicare alla CPU che è disponibile un dato nel Buffer Input o che il Buffer Output è vuoto e quindi scrivibile.

La sincronizzazione, come visto in generale per le interfacce di I/O può avvenire per

  • polling o a controllo del programma
  • interrupt o con interruzioni

Gestione a Polling[modifica]

L'interfaccia rende disponibili le informazioni di sincronizzazione nel registro di stato tramite due bit

  • BIF Buffer Input Full' ad indicare che il buffer in input è pieno, quindi contiene un valore che può essere letto dalla CPU
  • BOE Buffer Output Empty il buffer di uscita è vuoto e quindi scrivibile dalla CPU

Prima di eseguire il trasferimento, la CPU deve controllare lo stato dell'interfaccia, un esempio del programma potrebbe essere

Input

            MOV SI, 0             ; Inizializzazione dell'operazione di trasferimento
 WaitDato:  IN AL, Statuts        ; Lettura del registro di stato
            TEST AL, 1            ; valuta il registro di stato (BIF)
            JZ WaitDato           ; cicla le due operazioni precedenti se BIF = 0
            IN AL, BufferIn       ; altrimenti leggi il registro di buffer in input
            MOV Dati[SI], AL      ; memorizzane il valore in un array
            INC SI                ; incrementa il contatore per ulteriori letture
            CMP SI, N             ; verifica se l'operazione di lettura è terminata
            JNE WaitDato          ; se non è terminata torna ad attendere un dato


Output

            MOV SI, 0             ; Inizializzazione dell'operazione di trasferimento
 WaitDato:  IN AL, Statuts        ; Lettura del registro di stato
            TEST AL, 1            ; valuta il registro di stato (BOE)
            JZ WaitDato           ; cicla le due operazioni precedenti se BOE = 0
            MOV AL, Dati[SI]      ; altrimenti prepara il dato da inviare all'interfaccia
            OUT BufferOut, AL     ; e copialo
            INC SI                ; incrementa il contatore per ulteriori scritture
            CMP SI, N             ; verifica se l'operazione di scrittura è terminata
            JNE WaitDato          ; se non è terminata torna ad attendere la liberazione del buffer

Esempio di programmi per la gestione delle interfacce[modifica]

Pensiamo di voler gestire dei led mappati all'indirizzo 60H, per poter essere collegati al bus dati è necessario interfacciarli con un 373 che mette in 3-state le connessioni tra led e bus quando i primi non sono indirizzati, il programma, dopo l'inizializzazione

  Led    EQU  60H     ; etichetta per l'indirizzo dei led

comanda l'accensione di tutti i led

         MOV AL, FFH  ; costruisce il byte ...
         OUT Led, AL  ; ... da inviare all'interfaccia

Gestione ad Interrupt[modifica]

Nella gestione ad interrupt la CPU esegue un programma principale qualsiasi e viene interrotta da una richiesta di passaggio alla routine di servizio associata all'interruzione. La procedura chiamata dall'interfaccia deve quindi avere un prologo e un epilogo che permettano alla CPU di poter tornare ad eseguire il programma principale alla fine della routine di servizio

Programma principale

  MOV Index, 0
  MOV FineOp, 0
      .
      .                          ; in questa fase la CPU esegue altre operazioni e può accettare gli interrupt
      .
  WaitFineOp:  CMP FineOp, 1
               JNE WaitFineOp

La variabile FineOp è usata per la sincronizzazione, viene azzerata in fase di inizializzazione dal programma principale, ed impostata ad 1 dal gestore delle interruzioni (la routine di servizio) quando è completata l'operazione di I/O.

Routine di servizio

  PUSH AX              ; Memorizza i registri
  PUSH SI              ;
  MOV SI,Index         ; e inizializza il trasferimento
  IN AL,BufferIn       ; leggi dal buffer
  MOV DatiIn[SI],AL    ; salva i dati letti
  INC SI               ; incrementa il puntatore
  MOV Index,SI         ; e memorizzalo in una variabile accessibile alle successive routine
  CMP SI,N             ; verifica se il trasferimento è finito
  JNE Epilogo          
  MOV FineOp,1         ; se lo è indicalo anche al programma principale
Epilogo:   POP SI      ; ripristina i registri
           POP AX
           IRET        ; ritorna al programma principale