[successivo] [precedente] [inizio] [fine] [indice generale] [indice ridotto] [indice analitico] [home] [volume] [parte]


Capitolo 828.   SIMH e il PDP-11

SIMH(1) è un simulatore di hardware per una serie di vecchi elaboratori, tra i quali anche il famoso PDP-11. La simulazione implica generalmente l'accesso a file su disco che rappresentano, di volta in volta, l'immagine di un disco, di un nastro, di una stampante.

Per poter utilizzare SIMH occorre leggere la documentazione originale annotata alla fine del capitolo. Qui vengono annotate solo poche cose e in particolare ciò che riguarda il PDP-11.

828.1   Utilizzo normale

SIMH è costituito da un gruppo di programmi, ognuno specializzato per la simulazione di un certo tipo di elaboratore. Per esempio, per avviare la simulazione di un PDP-11, si usa normalmente il programma pdp11. Se si avvia il programma senza argomenti, si interagisce con il simulatore:

pdp11[Invio]

PDP-11 simulator V3.6-1

sim> 

Da questa modalità interattiva, si danno dei comandi, con i quali si specificano delle opzioni di funzionamento e si definisce l'uso di file-immagine di unità che devono essere gestite. Di norma si prepara uno script per non perdere tempo, come nell'esempio seguente:

SET     CPU  11/45
SHOW    CPU
;
; RL02 cartridge disks.
;
SET     RL   ENABLE
ATTACH  RL0  bsd_2.9_root_rl02.dsk
SHOW    RL0
;
; Boot.
;
BOOT    RL0

Le istruzioni che si possono dare dipendono molto dal tipo particolare di simulazione prescelto e sono documentate separatamente, rispetto alla guida generale sull'uso di SIMH. È comunque utile osservare che questi comandi non fanno differenza nell'uso di lettere maiuscole o minuscole, a parte quando si fa riferimento a file-immagine, che vanno scritti come richiede il sistema operativo esterno.

Per eseguire uno script è sufficiente avviare il programma seguito dal nome dello stesso:

pdp11 avvio.ini[Invio]

In alternativa, durante il funzionamento interattivo, è possibile usare il comando DO:

sim> do avvio.ini[Invio]

Durante il funzionamento interattivo del simulatore, è possibile concludere l'attività con il comando QUIT:

sim> quit[Invio]

Oltre al fatto che i comandi di SIMH possono essere espressi indifferentemente con lettere maiuscole o minuscole, va osservato che questi comandi possono essere abbreviati; pertanto, spesso si vedono esempi di utilizzo di SIMH con comandi apparentemente differenti, per il solo fatto che sono stati abbreviati.

828.2   Avvio e sospensione di una simulazione

In condizioni normali, salvo configurazione differente, SIMH associa alla combinazione di tasti [Ctrl e] la sospensione della simulazione. In pratica, una volta avviata la simulazione, questa combinazione ne produce la sospensione.

Una volta sospesa una simulazione, la si può riprendere, allo stato in cui si trovava, con il comando CONT; inoltre, è possibile salvare lo stato di funzionamento di una simulazione sospesa in un file, per poi recuperarla in un secondo momento e riprendere la simulazione da quella condizione.

Comando Descrizione
[Ctrl e] Sospende la simulazione.
CONT
Riprende la simulazione sospesa.
SAVE file
Salva in un file una simulazione sospesa.
RESTORE file
Recupera da un file una simulazione sospesa (da riprendere poi con il comando CONT).

828.3   Nastri virtuali

SIMH gestisce i nastri magnetici come file su disco, aventi però una struttura particolare che riproduce l'organizzazione dei dati nel nastro stesso. Il nastro, per sua natura, è suddiviso in record; pertanto, anche i file di SIMH devono riprodurre tale informazione.

Figura 828.4. Struttura dei dati che rappresentano un nastro virtuale per SIMH.

nastri di SIMH

In pratica, ogni record (che deve avere una quantità pari di byte) è preceduto e anche seguito da 32 bit che rappresentano la dimensione dello stesso, in byte, tenendo conto che il valore deve essere rappresentato in modalità little-endian. Alla fine del file, altri 32 bit a zero indicano la conclusione dello stesso (come se fosse l'inizio di un record vuoto. L'esempio che appare nella figura mostra la sequenza di questi dati; in particolare, il numero 0A00000016, va interpretato effettivamente come 0000000A16 (a causa dell'inversione little-endian), pari a 1010; pertanto, il record è composto da 10 byte.

Figura 828.5. Esempio di un nastro virtuale per SIMH, visto in esadecimale e secondo il codice ASCII. Il file originale è una sequenza di 100 byte contenenti le cifre numeriche da zero a nove (da 3016 a 3916 secondo il codice ASCII), suddiviso in record da 10 byte.

00000000  0a 00 00 00 30 31 32 33  34 35 36 37 38 39 0a 00  |....0123456789..|
00000010  00 00 0a 00 00 00 30 31  32 33 34 35 36 37 38 39  |......0123456789|
00000020  0a 00 00 00 0a 00 00 00  30 31 32 33 34 35 36 37  |........01234567|
00000030  38 39 0a 00 00 00 0a 00  00 00 30 31 32 33 34 35  |89........012345|
00000040  36 37 38 39 0a 00 00 00  0a 00 00 00 30 31 32 33  |6789........0123|
00000050  34 35 36 37 38 39 0a 00  00 00 0a 00 00 00 30 31  |456789........01|
00000060  32 33 34 35 36 37 38 39  0a 00 00 00 0a 00 00 00  |23456789........|
00000070  30 31 32 33 34 35 36 37  38 39 0a 00 00 00 0a 00  |0123456789......|
00000080  00 00 30 31 32 33 34 35  36 37 38 39 0a 00 00 00  |..0123456789....|
00000090  0a 00 00 00 30 31 32 33  34 35 36 37 38 39 0a 00  |....0123456789..|
000000a0  00 00 0a 00 00 00 30 31  32 33 34 35 36 37 38 39  |......0123456789|
000000b0  0a 00 00 00 00 00 00 00                           |........|
000000b8

SIMH offre solo strumenti di conversione da altri formati o di analisi del contenuto, ma manca la possibilità di creare un nastro a partire da file comuni e di estrarre poi i file stessi. Per questo occorre realizzare un proprio programma. Gli esempi che si vedono nei listati successivi, funzionano correttamente se la piattaforma prevede interi da 32 bit, rappresentati in modalità little-endian.

Listato 828.6. Programma per la conversione di un file comune nel formato adatto a SIMH per simulare i nastri magnetici. Dovrebbe esserne disponibile una copia presso <allegati/a2/convert_file_to_simh_tape.c>.

#include <stdio.h>
int main (int argc, char *argv[])
{
    int  iRecordLength;         // 32 bit, little endian.
    char acRecord[65535];       // 65535 is the max record length.
    int  iZero;
    int  iByteRead;
    int  iByteLeft;
    //
    iZero = '\0';
    //
    // Get the record length from command line argument.
    //
    sscanf (argv[1], "%d", &iRecordLength);
    //
    // Read and write data.
    //
    while (1)   // Loop forever.
      {
        //
        // Read from standard input one record.
        //
        iByteRead = fread (acRecord, 1, iRecordLength, stdin);
        //
        if (iByteRead == iRecordLength)
          {
            //
            // The record was read completely.
            //
            fwrite (&iRecordLength, 4, 1, stdout);
            fwrite (acRecord, iByteRead, 1, stdout);
            fwrite (&iRecordLength, 4, 1, stdout);
          }
        else if (iByteRead == 0)
          {
            //
            // Nothing was read. The file is finished.
            //
            fwrite (&iZero, 1, 4, stdout);
            break;
          }
        else if (iByteRead < iRecordLength)
          {
            //
            // The record was read partially: it must be
            // filled with zeroes.
            //
            iByteLeft = iRecordLength - iByteRead;
            //
            fwrite (&iRecordLength, 4, 1, stdout);
            fwrite (acRecord, iByteRead, 1, stdout);
            while (iByteLeft > 0)
              {
                fwrite (&iZero, 1, 1, stdout);
                iByteLeft--;
              }
            fwrite (&iRecordLength, 4, 1, stdout);
            //
            // The file is finished.
            //
            fwrite (&iZero, 1, 4, stdout);
            break;
          }
      } 
    return 0;
}

Il programma che si vede nel listato precedente converte un file normale in un «file su nastro», leggendo lo standard input e generando il risultato attraverso lo standard output. Se il file si chiama convert_file_to_simh_tape.c, si compila semplicemente così:

cc convert_file_to_simh_tape.c[Invio]

mv a.out convert_file_to_simh_tape[Invio]

Supponendo di volere convertire il file mio_file in un nastro virtuale, avente record da 1 024 byte, si può procedere così:

./convert_file_to_simh_tape 1024 < mio_file > mio_file.tap[Invio]

Una volta convertiti tutti i file che si vogliono usare, si possono mettere assieme in uno stesso «nastro virtuale», semplicemente concatenandoli, per esempio così:

cat file_0.tap file_1.tap ... > nastro_completo.tap[Invio]

L'estrazione di un file da un nastro richiede invece un procedimento più complesso. L'esempio riportato nel listato successivo mostra un programma che si limita a estrarre il primo file.

Listato 828.7. Programma per l'estrazione del primo file contenuto nell'immagine di un nastro virtuale di SIMH.

#include <stdio.h>
int main (int argc, char *argv[])
{
    int  iRecordLength;         // 32 bit, little endian.
    char acRecord[65535];       // 65535 is the max record length.
    int  iZero;
    int  iByteRead;
    int  iByteLeft;
    //    
    iZero = '\0';
    //
    // Read and write data.
    //
    while (1)  // Loop forever.
      {
        //
        // Read from standard input the record length.
        //
        iByteRead = fread (&iRecordLength, 1, 4, stdin);
        //
        if (iByteRead == 0)
          {
            //
            // The file is finished.
            //
            break;
          }
        else if (iByteRead < 4)
          {
            //
            // This should not happen.
            //
            return 1;
          }
        else if (iRecordLength == 0)
          {
            //
            // As the value is zero, this is the end of the
            // first file, and no other file is saved.
            //
            break;
          }
        else
          {
            //
            // Continue reading a record.
            //
            iByteRead = fread (acRecord, 1, iRecordLength, stdin);
            //
            if (iByteRead < iRecordLength)
              {
                //
                // The record is not complete.
                //
                return 1;
              }
            else
              {
                //
                // The record seems ok: write to output.
                //
                fwrite (acRecord, iByteRead, 1, stdout);
                //
                // Try to read from standard input the same
                // old record length (and ignore it).
                //
                iByteRead = fread (&iRecordLength, 1, 4, stdin);
                //
                if (iByteRead < 4)
                  {
                    //
                    // this should not happen!
                    //
                    return 1;
                  }
              }
          }
        //
        // Continue the loop.
        //
      } 
    return 0;
}

Il programma appena mostrato, si aspetta di leggere un file-immagine conforme alle specifiche di SIMH e non è in grado di gestire altre situazioni. Se si verificano errori, il programma termina di funzionare senza avvertimenti di qualunque sorta. Il file in ingresso viene atteso dallo standard input e il file estratto viene emesso attraverso lo standard output. Se il file si chiama estrai.c, si compila semplicemente così:

cc estrai.c[Invio]

mv a.out estrai[Invio]

Supponendo di volere estrarre il primo file contenuto nell'immagine mio_file.tap si può procedere così:

./estrai < mio_file.tap > file_0[Invio]

Dal momento che i dati in un nastro sono organizzati in record di dimensione uniforme, è normale che quanto estratto contenga qualche byte in più, ma a zero (0016). Di norma, i file che vengono archiviati su nastro hanno una struttura tale per cui questa aggiunta diventa ininfluente.

Listato 828.8. Programma completo per l'estrazione di tutti i file da un'immagine di un nastro di SIMH. Dovrebbe esserne disponibile una copia presso <allegati/a2/convert_simh_tape_to_file.c>.

#include <stdio.h>
int main (int argc, char *argv[])
{
    int  iRecordLength;         // 32 bit, little endian
    char acRecord[65535];       // 65535 is the max record length.
    int  iZero;
    int  iByteRead;
    int  iByteLeft;
    char aczRootFileName[252];
    char aczFileName[255];
    int  iFileCounter;
    FILE *pfOut;
    //    
    iZero        = '\0';
    iFileCounter = '\0';
    //
    // Get root file name.
    //
    sscanf (argv[1], "%s", aczRootFileName);
    //
    // Open the first output file.
    //
    sprintf (aczFileName, "%s-%03d", aczRootFileName, iFileCounter);
    pfOut = fopen (aczFileName, "w");
    printf ("%s\n", aczFileName);
    //
    // Read and write data.
    //
    while (1)
      {
        //
        // Read from standard input the record length.
        //
        iByteRead = fread (&iRecordLength, 1, 4, stdin);
        //
        if (iByteRead == 0)
          {
            //
            // The file is finished, although it is not
            // correctly ended. There are no more files.
            //
            fclose (pfOut);
            //      
            break;
          }
        else if (iByteRead < 4)
          {
            //
            // This should not happen, but close anyway.
            //
            fclose (pfOut);
            //
            return 1;
          }
        else if (iRecordLength == 0)
          {
            //
            // Then length of the next record is zero.
            // This is the end of the first file: prepare the next one.
            //
            fclose (pfOut);
            iFileCounter++;
            sprintf (aczFileName, "%s-%03d", aczRootFileName, iFileCounter);
            pfOut = fopen (aczFileName, "w");
            printf ("%s\n", aczFileName);
            //
          }
        else
          {
            //
            // The record length was read: no read the record.
            //
            iByteRead = fread (acRecord, 1, iRecordLength, stdin);
            //
            if (iByteRead < iRecordLength)
              {
                //
                // The record is not complete: close.
                //
                fwrite (acRecord, iByteRead, 1, pfOut);
                fclose (pfOut);
                //
                return 1;
              }
            else
              {
                //
                // The record seems ok: write to output.
                //
                fwrite (acRecord, iByteRead, 1, pfOut);
                //
                // Try to read from standard input the same
                // old record length (and ignore it).
                //
                iByteRead = fread (&iRecordLength, 1, 4, stdin);
                //
                if (iByteRead < 4)
                  {
                    //
                    // this should not happen: close.
                    //
                    fclose (pfOut);
                    //
                    return 1;
                  }
              }
          }
        //
        // Continue the loop.
        //
      } 
    //
    return 0;
}

Il programma che appare nell'ultimo listato è completo, in quanto estrapola tutti i file contenuti in un'immagine di nastro secondo SIMH. Il programma riceve dalla riga di comando la radice del nome dei file da creare, quindi genera una sequenza numerata con quella radice. In generale, l'ultimo file è vuoto e va ignorato.

Se il programma del listato è contenuto nel file simh_tape_to_file.c, si compila così:

cc convert_simh_tape_to_file.c[Invio]

mv a.out convert_simh_tape_to_file[Invio]

Supponendo di volere estrarre i file contenuti nell'immagine mio_file.tap si può procedere così:

./convert_simh_tape_to_file radice < mio_file.tap[Invio]

radice-000
radice-001
radice-002
...

In tal caso si ottengono i file radice-000, radice-001 e così di seguito.

828.4   Caratteristiche generali dei vari modelli PDP-11

I modelli di PDP-11 che sono esistiti hanno avuto caratteristiche abbastanza varie. Anche se si intende utilizzare solo un simulatore, è necessario scegliere il modello adatto al sistema operativo che si vuole installare. Le cose più importanti da sapere sono i tipi di bus ammissibili e la dimensione massima della memoria centrale.

Tabella 828.10. Caratteristiche generali dell'unità centrale, in ordine di anno di produzione.

Modello BusMemoria centraleAnno
PDP11/15Unibus 64 Kibyte 1970
PDP11/20Unibus 64 Kibyte 1970
PDP11/10Unibus 64 Kibyte 1972
PDP11/05Unibus 64 Kibyte 1972
PDP11/45Unibus, Fastbus 256 Kibyte1972
PDP11/50Unibus, Fastbus 256 Kibyte1972
PDP11/55Unibus, Fastbus 256 Kibyte1972
PDP11/35Unibus 256 Kibyte1973
PDP11/40Unibus 256 Kibyte1973
PDP11/03Q-bus 64 Kibyte 1975
PDP11/04Unibus 64 Kibyte 1975
PDP11/70Unibus, Massbus 4 Mibyte 1975
PDP11/34Unibus 256 Kibyte1976
PDP11/60Unibus 256 Kibyte1976
PDP11/23Q-bus 4 Mibyte 1979
PDP11/44Unibus, Private memory bus4 Mibyte 1979
PDP11/24Unibus 4 Mibyte 1980
PDP11/73Q-bus 4 Mibyte 1983
PDP11/21Q-bus 64 Kibyte 1983
PDP11/83Q-bus, Private memory bus4 Mibyte 1985
PDP11/84Unibus, Private memory bus4 Mibyte 1985
PDP11/53Q-bus 4 Mibyte 1987
PDP11/93Q-bus, Private memory bus4 Mibyte 1990
PDP11/94Unibus, Private memory bus4 Mibyte 1990

828.5   Simulazione unità a disco e a nastro

SIMH offre la simulazione di una gamma di dischi e nastri magnetici abbastanza ampia. La tabella successiva associa i tipi principali di dischi e nastri simulati all'unità di controllo e alla sigla usata da SIMH.

Tabella 828.11. I tipi principali di dischi e nastri gestiti da SIMH, associati ai nomi usati dai primi sistemi UNIX e BSD. Lo spazio disponibile viene calcolato in modo compatibile all'uso consueto: byte e multipli di byte.

dischi e nastri

828.6   Riferimenti


1) SIMH   software libero con licenza speciale


Appunti di informatica libera 2008 --- Copyright © 2000-2008 Daniele Giacomini -- <appunti2 (ad) gmail·com>


Dovrebbe essere possibile fare riferimento a questa pagina anche con il nome simh_e_il_pdp_11.htm

[successivo] [precedente] [inizio] [fine] [indice generale] [indice ridotto] [indice analitico] [home]

Valid ISO-HTML!

CSS validator!

Gjlg Metamotore e Web Directory