Italiano - English

Demo Kernel Multitasking

Sommario

    Esercitazioni di Informatica Industriale
    1. Architettura di un sistema basato su microprocessore Intel 8086
    2. Gestione degli Interrupt su micropocessori 80/86
    3. Programmable Interrupt Controller (PIC Intel 8259a)
    4. Demo Kernel Multitasking
    5. La Porta Seriale
    6. La Porta Parallela

    Viene presentato un semplice kernel multitasking per processore Intel 8086 compatibile in ambiente ms-dos

    Download
    mtask.zip

    Nei sistemi multitasking il il processore divide la sua attivita' tra diversi processi.

    APPLICAZIONI:

    - CENTRI DI CALCOLO i processi appartengono ad utenti diversi che sono indipendenti tra loro. Tutti però insistono sulla stessa macchina

    - SISTEMI REAL TIME sono quei sistemi che lavorano in stretta relazione con l'ambiente fisico esterno con il quale scambiano dati e segnali. Normalmente un processo fisico è caratterizzato da più elementi, gestiti da diversi moduli ed eseguiti contemporaneamente (in parallelo).

    In un sistema real time il tempo di risposta ai segnali esterni è una delle caratteristiche principali.

    PROGRAMMAZIONE SEQUENZIALE E MULTIPROGRAMMAZIONE

    nella programmazione sequenziale il problema e' quello di trovare un algoritmo che operi una trasfomazione dei dati in ingresso

    nella programmazione concorrente vi sono piu' moduli di programma (task) che vengono eseguiti in parallelo, spesso cooperando tra loro.

    i sistemi real-time possono essere realizzati con metodi di multitasking. e' infatti intuitivo scomporre il problema in sottoproblemi elementari ed associare ad ogniuno di essi un task pronto a rispondere alla prima esigenza

    il calcolatore e' per sua natura sequenziale

    la disposizione sequenziale di task paralleli, introduce forti legami tra funzioni che dovrebbero restare separate
     

    MultiTASKing

    • mtask e' un semplicissimo nucleo per la multiprogrammazione.
    • i problemi di sincronismo e protezione delle risorse vengono risolti con la natura stessa del nucleo
    • ogni task viene attivato periodicamente con periodo programmabile.
    • i task scaduti vengono attivati in sequenza
    • la priorita' dei task e' implicita nell'ordine in cui i task vengono dichiarati
    • quando un task viene attivato non viene mai interrotto
    • la base dei tempi viene fornita dal rtc con una risoluzione (tick) del ms
    • il tempo totale di esecuzione di tutti i task attivi deve essere inferiore al tick
    • un task puo' cambiare lo stato e il periodo di tutti i task dichiarati (compreso se stesso)

    Download mtask.zip

    MTASK.C

     

     
    /*====================== COSTANTI TIMER ===============================*/
     
    #define FMIN 1193180 /* valore da dividere per la freq desiderata
    */
     
    #define FBASE 1000 /* in Hz stabilisce il tick del sistema */
    #define TICKms 1 /* tick del sistema in ms */
    #define TICK55ms 55 /* numero di tick per la freq 18.2Hz */
     
    char mask8253; /* byte di controllo per 8253 prima di InstallMask*/
     
    /*================ VARIABILI INTERNE AL NUCLEO MTASK =================*/
     
    unsigned long int Ntick = 0; /* contatore dei tick trascorsi */
     
    struct /* lista degli eventi da eseguire */
    {     int periodo; /* periodo di attivazione in ms */
        int cnt; /* ms dall'ultima attivazione */
        char stato; /* ON/OFF */
        void (*evento)(void); /* funzione da attivare */
    } eventi[MAXEVENT];
     
    int numEvent = 0; /* numero eventi programmati */
     
    /*================ FUNZIONI INTERNE AL NUCLEO MTASK =================*/
    void interrupt ( *OldInt08)(void);
     
    /************************************************************************
    | InstallMtask
    -------------------------------------------------------------------------
    La seguente funzione serve a variare la frequenza del timer di sistema
    8253 sul canale 0 IRQ0. In questo modo cambia la frequenza con cui viene
    chiamato INT 08H. La nuova frequenza si ottiene inviando al timer il
    divisore che si ottiene dalla seguente formula:
                     1 193 180 ---->(FMIN)
    nuovo divisore = -----------
                     freq. desid.
     
    Il divisore di default è 65535 in modo che la frequenza sia 18.2 Hz cioè
    ogni 55ms. Questa frequenza è da tenere da conto inquanto INT 08H riginale
    serve a tenere aggiornato l'orologio del sistema e a controllare il motore
    del HD quindi qualsiasi sia la frequanza programmata il nuovo interrupt
    deve essere in grado di lasciare eseguire ogni 55 ms l'interrupt originale
    Questa routine inoltre cambia anche INT08H in modo che alla frequenza
    stabilita venga eseguita la funzione utente desiderata NewInt08 di seguito
    programmata.
    -----------------------------------------------------------------------*/
    char InstallMtask(void){ ... }
     
    char UnInstallMtask(void){... }
    /***********************************************************************
    | Aspetta
    -------------------------------------------------------------------------
    DESCRIZIONE: termina solo quando sono trascorsi il numero di millisecondi
    passatti
    -----------------------------------------------------------------------*/
    void Aspetta(int ms)
    {
      unsigned long int atTick = Ntick + ms;
      while(Ntick < atTick)
      {
        #ifdef DEBUG
        Kernel();
        #endif
      }
    }
     
    /***********************************************************************
    | OnEvent
    ------------------------------------------------------------------------
    DESCRIZIONE: attiva l'evento passato pone il contatore interno ad un valore
    pari al periodo in modo che viene immediatamente generato. Il contatore
    interno viene posto ad un valore pari al periodo in modo da fare
    immediatamente la prima attivazione senza aspettare che il periodo
    trascorra.
    PARAMETRI: il numero dell'evento desiderato. Cioè il valore tonato da
    AddEvent
    RITORNA: il vecchio stato
    -----------------------------------------------------------------------*/
    char OnEvent(int quale)
    {
      char oldstate = eventi[quale].stato;
      eventi[quale].stato = ON;
      eventi[quale].cnt = eventi[quale].periodo;
      return(oldstate);
    }
     
    /************************************************************************
    | OffEvent
    -------------------------------------------------------------------------
    DESCRIZIONE: disattivaa l'evento passato pone il contatore interno a 0
    PARAMETRI: il numero dell'evento desiderato. Cioè il valore tornato da
    AddEvento
    RITORNA: il vecchio stato
    -----------------------------------------------------------------------*/
    char OffEvent(int quale)
    {
      char oldstate = eventi[quale].stato;
      eventi[quale].stato = OFF;
      eventi[quale].cnt = eventi[quale].periodo;
      return(oldstate);
    }
     
    /************************************************************************
    | ChangeEventPeriod
    ------------------------------------------------------------------------
    DESCRIZIONE: cambia il periodo di attivazione dell'evento.
    pone l'evento a ON e se il contatore interno ha un valore superiore
    al periodo impostato, viene posto pari a quest'ultimo in modo da
    effettuare subito la prima commutazione
    PARAMETRI: il numero dell'evento desiderato. Cioè il valore tornato da
    AddEvento
    RITORNA: il vecchio periodo
    -----------------------------------------------------------------------*/
    int ChangeEventPeriod(int quale,int periodo)
    {
      int oldperiod = eventi[quale].periodo;
      eventi[quale].periodo = periodo;
      eventi[quale].stato = ON;
      if(eventi[quale].cnt > periodo)
        eventi[quale].cnt = periodo;
      return(oldperiod);
    }
     
    /***********************************************************************
    | AddEvent
    ------------------------------------------------------------------------
    DESCRIZIONE: imposta l'evento nella prima posizione disponibile. L'evento
    ha una priorità inferiore a tutte i precedenti e superiore a tutti i
    successivi. Il primo evento viene generato allo scadere del periodo,
    quindi sul fronte di discesa.
    PARAMETRI: il periodo di attivazione dell'evento,il suo stato e la funzione
    da attivare;
    RITORNA: il numero dell'evento
    ----------------------------------------------------------------------*/
    int AddEvent(int periodo,char stato, void (*evento)(void))
    {
      if(numEvent < MAXEVENT)
      {
        eventi[numEvent].periodo = periodo;
        eventi[numEvent].cnt = 0;
        eventi[numEvent].stato = stato;
        eventi[numEvent].evento = evento;
        return(numEvent++);
      }
    return(FULL);
    }
     
    /***********************************************************************
    | Kernel
    ------------------------------------------------------------------------
    DESCRIZIONE: questa funzione viene chiamata ogni ms da clock del 8253.
    cerca nell'elenco degli eventi quello il cui contatore interno e' pari
    al periodo interno, e lo attiva. Dopo averlo attivato azzera il contatore
    interno. successivamente, In gni caso incremento i contatori interni.
    Verifico poi che non siano trascorsi 55ms ed eventualmente attivo il
    vecchio int08h. Infine incremento la variabile Ntick che conta il numero
    degli impulsi trascorsi dal momento dell'installazione di Mtask
    L'attivazione degli eventi avviene sul fronte di salita del clock.
    mentre l'incremento dei contatori sul fronte di discesa. Questo implica
    che prima eseguo la verifica, eventualmente attivo ed azzero, poi incremento.
    PARAMETRI:
    RITORNA:
    -----------------------------------------------------------------------*/
    #ifdef DEBUG
    void Kernel(void)
    #else
    void interrupt Kernel(void)
    #endif
    {
      char i;
      static int cont08h =55;
      for(i=0;i<eventi[i].periodo) /* e se è scaduto */
          {
            (eventi[i].evento)(); /* attivo l'evento */
            eventi[i].cnt = 0; /* azzero il contatore */
          }
          eventi[i].cnt++; /* incremento i cnt di TUTTI gli elementi ON */
        }
      }
     
    /*se necessario chiamo il vecchio int08h per mantere il clock di sistema */
    if(cont08h == TICK55ms) /* ogni 55 ms */
    {
      cont08h = 0; /* se passati 55ms azzero il contatore */
      #ifndef DEBUG
        OldInt08(); /* chiamo il vecchio interrupt */
      #else
        sound(1000);
        nosound();
      #endif
    } else
      #ifndef DEBUG
        outp(0x20,0x20); /* mando EOI al 8259 per riattivare IRQ0 */
      #endif
     
    cont08h++; /* incremento il contatore per i 55m */
    Ntick++; /* incremento il contatore generale */
    }
     
    unsigned long int GetNtick() {return Ntick;}
    prova di MTASK
     
    #ifdef PROVA_MTASK
     
    int ok =0;
    void Suona()
    {
        sound(10000);
        OffEvent(0);
    }
     
    void Stop()
     
    {
        nosound();
        ok = 1;
    }
     
    /*******************************************************************/
    void main()
    {
        int primo,secondo;
        primo = AddEvent(0,ON,Suona);
        secondo = AddEvent(3000,ON,Stop);
        InstallMtask();
        while(ok==0)
        {
          #ifdef DEBUG
            Kernel();
          #endif
        }
        UnInstallMtask();
    }
    #endif

     

    Vota questa pagina:

    0 Commenti:

    Lascia il tuo commento:

    Note:
    • La tua email non è obligatoria e non sarà visibile in alcun modo
    • Si prega di inviare solo commenti relativi a questa pagina
    • Commenti inappropriati o offensivi saranno modificati o eliminati
    • Codici HTML non sono consentiti. Prego usare i BB code:
      [b]bold[/b], [u]underline[/u], [i]italic[/i], [code]code[/code]
    Il codice, le illustrazioni e gli esempi riportati in questa pagina sono solo a scopo illustrativo. L'autore non prende alcuna responsabilità per il loro utilizzo da parte dell'utente finale.
    Questo materiale è di proprietà di Pk Lab ed è utilizzabile liberamente a condizione di citarne la fonte.