1. A breve aggiorneremo la piattaforma di Reboot per risolvere alcuni problemi con i plug-in, quindi chiediamo ancora un po' di pazienza, Lo staff di Reboot

[Guida] OSDev 2.0 - Come creare un sistema operativo in C++ - Lo schermo e la ISO

Discussione in 'Software' iniziata da iostream, 18 Ago 2017.

  1. iostream

    iostream Phoenix Wright

    Iscritto:
    13 Ago 2016
    Messaggi:
    4.913
    Like ricevuti:
    1.639
    [​IMG]
    Salve a tutti, in questo secondo capitolo vi farò vedere come si scrive del testo sullo schermo (anche colorato).

    È consigliata sia la lettura del lessico sia la lettura necessaria della prima parte


    Lo schermo


    Pilotare lo schermo, in maniera testuale, è semplicissimo: basta scrivere dei valori su degli indirizzi di memoria. Una voce dello schermo occupa 16 bit (in C++ è una unsigned short) ed è composto dai seguenti bit:
    Bit 0-7Bit 8-15
    Il colore del testo è della scrittaIl carattere
    Ad ogni colore invece corrisponde un valore esadecimale (quindi di quattro bit):
    • 0x00 = 0000 = Nero
    • 0x01 = 0001 = Blu
    • 0x02 = 0010 = Verde
    • 0x03 = 0011 = Ciano
    • 0x04 = 0100 = Rosso
    • 0x05 = 0101 = Magenta
    • 0x06 = 0110 = Marrone
    • 0x07 = 0111 = Grigio
    • 0x08 = 1000 = Grigio scuro
    • 0x09 = 1001 = Azzurro
    • 0x0A = 1010 = Verde chiaro
    • 0x0B = 1011 = Celeste
    • 0x0C = 1100 = Rosso chiaro
    • 0x0D = 1101 = Magenta chiaro (fucsia)
    • 0x0F = 1111 = Bianco
    Quindi creiamo una cartella include nella nostra cartella di lavoro e iniziamo a scrivere in screen.h:
    Codice:
    // Include guard, che serve ad evitare che lo stesso file venga incluso due volte
    #ifndef _SCREEN_H_INCLUDED
    #define _SCREEN_H_INCLUDED
    
    // Constanti che rappresentano i colori possibili
    const char SCREEN_NERO = 0x00;
    const char SCREEN_BLU = 0x01;
    const char SCREEN_VERDE = 0x02;
    const char SCREEN_CIANO = 0x03;
    const char SCREEN_ROSSO = 0x04;
    const char SCREEN_MAGENTA = 0x05;
    const char SCREEN_MARRONE = 0x06;
    const char SCREEN_GRIGIO = 0x07;
    const char SCREEN_GRIGO_SCURO = 0x08;
    const char SCREEN_AZZURRO = 0x09;
    const char SCREEN_VERDE_CHIARO = 0x0A;
    const char SCREEN_CELESTE = 0x0B;
    const char SCREEN_ROSSO_CHIARO = 0x0C;
    const char SCREEN_MAGENTA_CHIARO = 0x0D;
    const char SCREEN_BIANCO = 0x0F;
    
    // Fine dell'include guard
    #endif
    Una constante è un valore che non si può modificare, mentre una variabile è un valore che si può modificare. Ad esempio se, con questo codice faccio:
    Codice:
     VGA_VERDE = 18; 
    Il compilatore mi darà un errore sul fatto che VGA_VERDE è stata dichiarata come constante. Se invece non ci fosse stato const (la parola che dice al compilatore che questa è una constante) prima di char (la grandezza della constante, in questo caso 1 byte [due caratteri hex]. I tipi possibili sono char (8 bit), short (16 bit), int (32 bit). I tipi con unsigned prima del tipo (ad esempio unsigned int) indicano che il valore è senza segno. Mentre i tipi senza unsigned indicano che sono con segno. Ad esempio un unsigned char andrà da -127 a +127, mentre un unsigned char andrà da 0 a 256. Per calcolare il valore massimo di un tipo bisogna fare (in questa formula t è la dimensione del tipo,, ^ significa che è una potenza [letto come alla]):
    Codice:
    2^t - 1
    Ora aggiungiamo le definizioni delle funzioni del namespace Screen (questo codice va tra la fine dell'include guard e la fine delle definizioni delle costanti):
    Codice:
    namespace Screen {
        /* Funzione che cancella il contenuto dello schermo. Il contenuto nuovo sarà il colore di sfondo */
        void ClearScreen();
    
         /* Funzione che imposta il colore dello schermo */
         /* Parametri richiesti: fg = Testo, bg = Sfondo */
         void SetScreenColor(char fg, char bg);
    
          /* Funzione che permette di stampare un carattere */
          /* Parametri: c = Carattere */
          void PutChar(char c);
    
          /* Funzione che stampa una stringa */
          /* Parametri: s = La stringa da stampare */
          void PutString(const char* s);
    
          /* Funzione che inzializza le variabili */
          void ScreenInit();
    }
    E adesso creiamo un'altro file screen.cpp nella cartella principale:
    Codice:
    #include "include/screen.h"
    
    unsigned short* VMem;           // Puntatore alla memoria video
    unsigned short Color;              // Colore con cui scrivere
    
    int x;                                         // Coordinate a cui scrivere
    int y;
    
    // ----- Lo scopo delle funzioni è scritto in "include/screen.h" -----
    
    
    void Screen::ClearScreen() {
        // Per ognuno dei 2000 (80*25) caratteri dello schermo, riempilo con uno spazio del colore corrente
        for (int i=0; i<2000; ++i)
            VMem[i] = Color | 0x0020;
    }
    
    void Screen::SetScreenColor(char fg, char bg) {
        Color = (fg | bg << 4) << 8;
    }
    
    // Funzione che va a capo e, se necessario, gestisce lo scroll
    void newline() {
        if (y++ == 25) {  // Se incrementando la Y raggiunge il massimo
            // Sposta tutto una linea più sopra e cancella l'ultima linea
            for (int i=0; i<1920; ++i) {
                 VMem[i] = VMem[i+80];
                 VMem[i+80] = Color | 0x0020;
            }
           // Rimetti la Y al valore massimo consentito
           y = 24;
        }
        x = 0;  // Resetta la X
    }
    
    void Screen::PutChar(char c) {
        switch (c) {            // Il carattere può essere:
            case '\t':            // Una tabulazione (stampa 4 spazi)
                for (int i=0; i<4; ++i)
                    PutChar(' ');
               break;
             case '\n':          // Un'andata a capo (chiama la funzione che la gestisce
               newline();
               break;
             default:           // Un carattere normale
                VMem[i] = Color | c; // Metti il carattere nell'indirizzo di memoria specifico
               if (x++ == 80)            // Incrementa la posizione X e se raggiunge il massimo fai una nuova linea
                   newline();
                break;   
        }
    }
    
    void Screen::PutString(const char* s) {
         // Per ogni carattere della stringa mettilo nello schermo
         // s[i] significa finchè il carattere non è \0, ovvero fine stringa
         for (int i=0; s[i]; ++i)
             PutChar(s[i]);
    }
    
    void Screen::ScreenInit() {
         VMem = (unsigned short*)0xB8000; // La memoria video è all'indirizzo 0xB8000
         SetScreenColor(SCREEN_GRIGIO, SCREEN_NERO); // Colore stile DOS
         x = 0;                                                // Coordinate a zero
         y = 0;
        ClearScreen();                                  // Cancella il contenuto dello schermo
    }
    Il kernel


    Adesso il kernel dovrà avere questa struttura per provare la libreria dello schermo:
    Codice:
    #include "include/screen.h"
    
    void main() {
        Screen::ScreenInit();
        Screen::PutString("Ciao da reboot.ms!");
    }
    Penso che il codice sia abbastanza leggibile grazie ai commenti (le linee con // oppure il testo circondato da /* e */)
    Creiamo un file ISO

    Per prima cosa dovrete scaricare uno di questi pack (a seconda del sistema operativo):
    Quello per Linux contiene il Makefile con supporto al GRUB e le varie directory necessarie. Quello per Windows il Makefile con ISOLinux e le sue directory. Dovrete estrarli nella directory dell'OS sostituendo i file già presenti

    Avviamolo da QEMU


    Fate un bel "make all" e fate da linea di comando:
    Codice:
    qemu-system-i386 -cdrom os.iso


    Forse questo pomeriggio uscirà la parte sulla memoria virtuale. Stay tuned! (chi è che lo diceva??)

    Capitolo successivo
     
    #1
    Ultima modifica: 25 Ago 2017
    A Unknown, zoomx, IlVampirelloXY e 1 altro utente piace questo messaggio.
  2. MODD3R

    MODD3R Ospite

    Lo dico io stay tuned! XD
     
    #2
Sto caricando...

Condividi questa Pagina