Dentro i Sistemi Operativi – il Debug Monitor

In questa serie di articoli analizzeremo il funzionamento di alcuni tipi di sistemi operativi, cercando di mostrarne le caratteristiche salienti ed i meccanismi interni.

Per iniziare, partiremo dall’analisi di un software che, pur non essendo un vero e proprio sistema operativo, presentava le funzioni basilari per leggere il contenuto della RAM, scrivere in essa e, opzionalmente, caricare e salvare intere regioni di memoria su dispositivi secondari (spesso unità a nastro magnetico o perforato).

Stiamo parlando del Machine Code Monitor.

Tali Monitor costituivano il principale software in dotazione dei primissimi sistemi di calcolo personale, parliamo di trainers e di home computers, nel periodo a cavallo tra gli anni ’70 e ’80. Leggendo e scrivendo un byte alla volta, è possibile inserire nella RAM direttamente gli opcode in linguaggio macchina, realizzando così i primi rudimentali programmi.

Generalmente bisognava scrivere prima il programma su carta, aiutandosi con i diagrammi di flusso o altro sistema schematico (pseudo codice, o altro), poi tradurre in linguaggio Assembly il programma, successivamente bisognava tradurre il listato in codice macchina e inserire i valori numerici dei singoli byte tramite il Monitor.

Versioni più evolute dei Monitor prevedevano anche un Assembler e un Disassembler, che evitavano il processo di trascrizione manuale degli opcode. Tali Monitor avanzati possiedono spesso anche delle rudimentali funzioni di debugging, tipicamente gestiscono i breakpoints e lo stepping, per cui vengono anche detti Debug Monitor.

Le funzioni principali di un tipico Debug Monitor:

Assemble: traduce una riga da Assembly a linguaggio macchina, e scrive il risultato all’indirizzo specificato.

Disassemble: legge a partire dall’indirizzo specificato effettuando la traduzione da linguaggio macchina ad Assembly.

Registers: visualizza il contenuto dei registri.

Run: carica l’indirizzo specificato sul Program Counter, di fatto serve ad eseguire un pezzo di codice che inizia all’indirizzo specificato.

Put: inserisce un byte all’indirizzo specificato.

Dump: legge un blocco di Ram e lo stampa a schermo (solitamente in esadecimale).

Load: legge un blocco di dati dalla memoria secondaria (nastro o altro) e lo carica a partire dall’indirizzo dato.

Save: prende un blocco dalla Ram e lo salva su memoria secondaria.

Per eseguire queste semplici operazioni, il Debug Monitor si serve di ulteriori funzioni non direttamente visibili all’utente, ma presenti in memoria a determinati indirizzi e che completano quello che potremmo definire come un rudimentale Sistema Operativo. Alcuni esempi di funzioni o routines, in gergo, sono:

PutChar: scrive un carattere a schermo (è la base dell’output su schermo).

PutString: si serve di PutChar per scrivere un’intera stringa di caratteri.

WriteByte: invia un byte verso una periferica di Output, usato anche per scrivere su memoria secondaria, o per settare dei registri harware.

ReadByte: legge un byte da una periferica di Input, ad esempio la tastiera.

CallMonitor: avvia il Debug Monitor.

Questo è il minimo indispensabile per poter costruire un Debug Monitor, ed è solitamente usato anche dai programmi utente per leggere e scrivere sulle periferiche, acquisire gli Input da tastiera o nastri, inviare gli Output su display o stampante. Possono inoltre essere combinate in routine di più alto livello, per eseguire compiti più sofisticati come ad esempio la gestione di un filesystem, una porta di comunicazione seriale / parallela, ecc…

In tale ambiente è chiaro che un solo programma alla volta può essere eseguito, e tale programma agisce a basso livello su ogni aspetto dell’hardware sottostante, a meno di eventuali astrazioni previste da tale rudimentale Sistema Operativo. So che in questi casi è un po’ esagerato parlare di vero e proprio Sistema Operativo, ma i concetti che introdurremo man mano ci guideranno verso la definizione di OS sempre più sofisticati, fino a giungere a quelli che utilizziamo attualmente nei nostri computer moderni.

L’astrazione è il concetto chiave che approfondiremo nel prossimo articolo, in cui presenteremo un esempio concreto di sistema operativo basato su una semplice raccolta di routines come quelle presentate: il KERNAL dei computer Commodore a 8 bit.

Press ESC to close