Struttura dei dischi 1541

Alberto 03-03-2004.
Categoria: Hardware

Chi ha posseduto un C64, è probabile che avesse anche un drive 1541 e relativi  floppy da 5.25", ma che lo usasse semplicemente per caricare e, al massimo, salvare programmi.

In questo articolo cercheremo di andare un pò più a fondo e di vedere da vicino le principali caratteristiche dei dischi del 1541 e, soprattutto, che cosa è possibile fare col drive sui dischi stessi.

Ogni disco memorizza dati su TRACCE e SETTORI.

Una traccia è costituita da un numero variabile di settori, ciascuno dei quali è un blocco di dati lungo 256 byte. Ogni byte è paragonabile ad un singolo dato.

I dischi del 1541 sono formati 40 tracce fisiche, ma solo 35 di queste possono essere usate dal DOS (il sistema operativo del drive 1541 che gestisce i dati sul disco stesso).

Le tracce sono settori circolari concentrici allocati a partire dal bordo esterno del disco (traccia n. 1) fino al bordo interno (traccia n. 35).
Il seguente disegno riassume quanto detto finora:

Chiaramente, le tracce più esterne sono notevolmente più estese di quelle più interne, e, come è facile intuire, sono quelle che contengono il maggior numero di settori.

In particolare, le tracce da 1 a 17 contengono ciascuna 21 settori, le tracce da 18 a 24 ne contengono 19, le tracce da 25 a 30 ne contengono 18, le tracce da 31 a 35 ne contengono 17.

Quindi, i settori gestibili su disco sono 21*17 + 19*7 + 18*6 + 17*5 = 683.

Di questi, però, solo 664 possono essere usati per memorizzare dati e programmi dell'utente. I 19 blocchi riservati vengono usati dal DOS per aggiornare la lista e il tipo dei file contenuti sul disco, e si trovano tutti nella traccia n. 18.

Il primo settore di questa traccia contiene il BAM (block availability map), l'etichetta e l'ID del floppy, e la versione del DOS che è in grado di gestire il disco stesso. Il BAM è un registro di 140 byte che tiene conto dei blocchi liberi presenti sul disco stesso. Ogni volta che si salva un file su disco o lo si cancella, questo registro viene autoticamente aggiornato dal DOS.

L'etichetta e l'ID del disco rappresentano il nome e il codice identificativo del floppy, e possono essere modificati dall'utente. La versione del DOS, invece, non è modificabile.

Ciascuno dei restanti 18 settori è detto "BLOCCO DI GESTIONE FILE" ed è così organizzato:

  • i primi 2 byte contengono la traccia e il settore del successivo blocco di gestione file (in esadecimale)
  • i restanti 254 byte sono suddivisi su 8 campi file, ciascuno dei quali contiene informazioni sul nome, sul tipo e sulla posizione del file nel disco.

Ogni campo file (tranne il primo) è allocato lasciando 2 byte vuoti dal campo file che lo precede, in modo da distribuire i dati uniformemente su tutto il settore.

Abbiamo dato una panoramica molto generale della struttura dei dischi 1541. Vediamo ora come scrivere listati Basic con i quali poter gestire efficacemente i dischi.

Si dà per scontata la conoscenza dei rudimenti del Basic, e si rimanda, per eventuali dubbi, alla revisione italiana della 'Guida di Riferimento del Programmatore' presente su questo sito (link temporaneamente sospeso - ndR).

Per scambiare informazioni col drive dovremo porre in testa ai nostri programmi un'istruzione del tipo:

OPEN F%, P%, C%, A$

dove

F% assume significati diversi
se A$ è un nome di file, F% è un identificativo di quel file
se A$ è un comando, F% è un canale associato al comando da eseguire per questo parametro useremo un numero compreso tra 1 e 127.

P% rappresenta la periferica con cui vogliamo comunicare; nel nostro caso, siccome vogliamo comunicare col primo drive, sarà sempre uguale a 8.

C% è il tipo di canale di comunicazione da aprire per trasmettere dati alla periferica, in particolare useremo C compreso tra 2 e 14 ogni volta che vogliamo inviare o ricevere byte dal drive useremo C = 15 ogni volta che vogliamo inviare un comando al drive.

Prendiamo un disco vuoto, formattiamolo e assegnamogli un'etichetta e un ID

5 REM INIZIALIZZA DISCO
10 OPEN2,8,15,"I":REM POSIZIONA LA TESTINA DEL DRIVE SULLA TRACCIA N. 18
15 PRINT#2,"NEW0:PROGRAMMI,64":REM FORMATTA IL DISCO E PONE COME ETICHETTA "PROGRAMMI"
16 REM E COME ID "64"
20 CLOSE2:REM CHIUDE IL CANALE DI COMUNICAZIONE

Alcune osservazioni:nella riga 10 abbiamo definito 2 come canale di comando, e vi abbiamo trasmesso il comando "I" ( inizializza ), che posiziona la testina del drive sulla traccia riservata alla gestione dei file su disco. Questa operazione è svolta in automatico dal DOS ogni volta che si carica o si salva un programma.

La riga 15 invia al canale 2 un'altro comando:quello di formattare il disco. Il DOS posiziona la testina sulla traccia più esterna (la n. 1) e cancella eventuali dati presenti sul disco, spostandosi man mano verso la traccia più interna (la n. 35).

Quando ha finito di cancellare i dati presenti sull'ultima traccia, la testina si riporta sulla traccia riservata al DOS. Infine, la riga 20 chiude il canale di comunicazione per liberare risorse.

Se diamo il comando diretto:

LOAD"$", 8
e LIST

vedremo apparire a schermo quanto segue

0 "PROGRAMMI " 64 2A
664 BLOCKS FREE.

Il DOS ha caricato il direttorio del disco, leggendo il primo settore della traccia 18 e il primo campo file del secondo settore; avendo trovato come primo nome di file una stringa nulla, ha concluso che il disco non ha programmi memorizzati al suo interno, ed è ritornato al Basic. '2A' è la versione del DOS supportata dal floppy.

Ripuliamo la memoria con NEW e passiamo al prossimo listato.

Il seguente programma è un Word Processor che consente di scrivere a schermo stringhe qualsiasi e di memorizzarle in un file sul disco, finchè non viene letta la stringa terminatrice "STOP".

5 REM WORD PROCESSOR
10 OPEN 2, 8, 3, "0:WORDPROC, PRG, W" :REM REGISTRA FILE "WORDPROC" NEL DIRETTORIO
11 REM E NE CONSENTE LA SCRITTURA
15 INPUT "STRINGA - 'STOP' TERMINA"; A$ :REM LEGGE STRINGA
20 IF A$="STOP" THEN GOTO 35 :REM LA SCRIVE NEL FILE "WORDPROC"
25 PRINT#2, A$ :REM FINCHE' NON LEGGE LA STRINGA "STOP"
30 GOTO 15 :REM RIPETE CICLO
35 CLOSE 2 :REM CHIUDE IL CANALE

Stavolta abbiamo aperto un canale dati perchè volevamo creare su un file e scriverci sopra dei byte. Alla riga 10, PRG è il tipo di programma che abbiamo creato (un normale file sequenziale), e W è la modalità con cui l'abbiamo utilizzato ( Write=scrittura).

Diamo di nuovo LOAD"$", 8 e LIST. Questo è quel che appare a video:

0 "PROGRAMMI " 64 2A
1 "WORDPROC" PRG
663 BLOCKS FREE.

Se non abbiamo scritto molte stringhe, dovremmo aver occupato un solo blocco dati su disco; ciò significa che ne abbiamo ancora 663 a disposizione. Il DOS ha trovato il nome "WORDPROC" nel primo campo file del secondo settore della traccia 18.

Vogliamo ora conoscere la posizione dei blocchi dati usati dal file "WORDPROC".

Battiamo NEW e digitiamo il seguente programma:

5 REM TROVA BLOCCHI USATI DAL FILE
10 INPUT "NOME FILE"; F$ :REM CHIEDE DI INSERIRE IL NOME DEL FILE DI CUI CERCARE I BLOCCHI DATI
15 OPEN 2, 8, 15 :REM CANALE DI COMANDO
20 OPEN 3, 8, 3, "#" :REM APRE CANALE DATI PER LEGGERE IN MODALITA' ACCESSO CASUALE
25 CB=1:CP=5:T=18 :REM INIZIALIZZA BLOCCO CORRENTE, POSIZIONE CORRENTE NEL BLOCCO E
26 REM TRACCIA INIZIALE
30 GOSUB 300
35 I=I+1 : GET#3, A$ : S$=S$+A$
40 IF S$ LEFT$(F$, I) THEN 50
45 GOTO 35
50 IF LEN(S$) = LEN(F$)+1 THEN 75 :REM FILE TROVATO!
55 I=0:S$=""
60 CP=CP+32 :REM SPOSTA LA TESTINA SUL CAMPO FILE SUCCESSIVO
65 GOSUB 300
70 GOTO 35 : REM LEGGE NEL CAMPO FILE SUCCESSIVO
75 PRINT "TRACCIA", "SETTORE"
80 CP=CP-2:GOSUB 300 :REM LEGGE LOCAZIONE DEL PRIMO BLOCCO DATI
85 GET#3, T$, B$
90 IF (ASC(T$+CHR$(0))=0) THEN 205 :REM SE PROSSIMA TRACCIA=0, ESCE
95 PRINT ASC(T$+CHR$(0)), ASC(B$+CHR$(0)) :REM LA STAMPA
100 T=ASC(T$+CHR$(0)):CB=ASC(B$+CHR$(0)):CP=0:GOSUB 305 :REM SETTA NUOVE LOCAZIONI
105 GOTO 85 :RIPETE IL CICLO
300 IF CP=261 THEN CP=5:CB=CB+1 :REM CAMBIA SETTORE DEL DIRETTORIO
301 IF CB=19 THEN 200 :REM CAMPI FILE FINITI; ESCE CON UN MESSAGGIO D'ERRORE
305 PRINT#2, "B-R:"3; 0; T; CB :REM SETTA POSIZIONE BLOCCO IN TRACCIA
310 PRINT#2, "B-P:"3; CP :REM SETTA POSIZIONE BYTE NEL BLOCCO
315 RETURN
200 PRINT "FILE NON TROVATO"
205 CLOSE 3:CLOSE 2
210 END

Lanciamo il programma e chiediamo di conoscere i blocchi occupati dal file 'WORDPROC' salvato in precedenza.

NOME FILE? WORDPROC < return >
TRACCIA SETTORE
17 0

Abbiamo scoperto che il file WORDPROC è stato salvato nella traccia 17, al settore 0 ed è quindi composto da un solo blocco dati (come già sapevamo dall'analisi del direttorio).

Il programma è un pò complesso, e necessita di qualche spiegazione. All'inizio, il C64 chiede di immettere il nome del file del quale cercare i blocchi dati; quindi, viene aperto un canale di comando per impostare la traccia, il blocco e la posizione inziale della testina e un canale dati per l'accesso casuale al file attraverso la stringa "#"; questa modalità di accesso è necessaria per poter spostare la testina nella zona voluta all'interno di un singolo blocco del direttorio.

Il programma inizializza la posizione della testina con la routine alle righe 300-315, poi legge la stringa contenuta nel primo campo file del secondo settore del direttorio; appena vi è una discordanza col nome di file cercato controlla se la discordanza si è verificata oltre la lunghezza del nome di file inserito; se ciò non è vero, il programma sposta la testina sul prossimo campo file, eventualmente cambiando settore del direttorio se sono già stati analizzati tutti gli 8 campi file del settore corrente. Se nell'ottavo campo file del 18esimo settore del direttorio non è stato trovato il nome del file cercato, il programma termina segnalando all'utente che il file cercato non è presente sul disco.

Non appena viene trovato il file cercato, la testina viene spostata nella seconda posizione del campo file, dove vengono letti traccia e settore del primo blocco dati; essi vengono quindi stampati a schermo. Una volta spostatasi sul primo blocco dati del file ne vengono letti i primi 2 byte:questi contengono rispettivamente la traccia ed il settore del blocco successivo; se la traccia è diversa da 0, vengono stampati a schermo, e così via... La ricerca termina quando il primo byte del blocco (il puntatore alla traccia del successivo blocco dati) è uguale a 0:questo valore indica al C64 che il file non usa altri blocchi dati.

Il programma elenca i blocchi dati usati da un qualsiasi file su disco: si lascia al lettore la - banalissima! - implementazione di un sistema per visualizzare direttamente a schermo il numero di blocchi usati dal file: questo può essere utile nel caso in cui un file utilizzi molti blocchi dati, e non sia possibile determinarne la quantità perchè il loro elenco occupa più di una schermata.

Concludiamo questa nostra rapida carrellata sulle caratteristiche dei dischi 1541 con la descrizione dei file relativi. I file relativi permettono l'organizzazione dei dati in diversi blocchi dati (lunghi sempre 256 byte) ciascuno dei quali contiene un certo numero di RECORD, di lunghezza variabile a piacere. Come avrai capito, questi file sono utili per gestire liste ed elenchi. Noi, però, faremo qualcosa di più interessante che inserire semplicemente dati all'interno dei record; realizzeremo una 'agenda elettronica'. Vediamo come.

Al solito, ripuliamo la memoria Basic e digitiamo quanto segue:

5 REM AGENDA ELETTRONICA
10 PRINT CHR$(147) :REM PULISCE SCHERMO
15 PRINT "SCEGLI UNA OPZIONE ( 1-4 )":PRINT
20 PRINT "1. INSERISCI NOME"
25 PRINT "2. CANCELLA NOME"
30 PRINT "3. RICERCA NOME"
35 PRINT "4. ESCI"
40 GET A$:IF (A$ < "1") OR (A$ > "4") THEN GOTO 40 :REM ATTENDE SCELTA UTENTE
45 ON VAL(A$) GOTO 100, 210, 210, 400 :REM SCEGLIE LA ROUTINE ADATTA
100 INPUT "NOME"; N$
105 INPUT "COGNOME"; C$
110 INPUT "NUMERO"; T$
115 PRINT "SALVATAGGIO DATI IN CORSO. . . "
120 OPEN 15, 8, 15
125 OPEN 2, 8, 2, "AGENDA, L, "+CHR$(30) :REM CREA FILE CON UN BLOCCO DATI AVENTE RECORD DI 30 BYTE
130 I=1:J=0:X=0 :REM INIZIALIZZA PUNTATORE AL RECORD E POSIZIONE NEL RECORD
135 PRINT#15, "P"CHR$(2)CHR$(I)CHR$(J)CHR$(X)
140 GET#2, A$:IF ASC(A$+CHR$(0))255 THEN 155 :REM RECORD OCCUPATO, VA AL SUCCESSIVO
145 GOSUB 180
150 GOTO 190
155 I=I+1
160 IF I256 THEN 135
165 I=0:J=J+1
170 GOTO 135
175 X=X+10 :REM SPOSTA PUNTATORE PER SCRIVERE NEL CAMPO SUCCESSIVO
180 PRINT#15, "P"CHR$(2)CHR$(I)CHR$(J)CHR$(X)
185 RETURN
190 PRINT#2, N$:GOSUB 175
195 PRINT#2, C$:GOSUB 175
200 PRINT#2, T$:CLOSE 2:CLOSE 15:GOTO 10
210 INPUT "NOME"; N$
215 PRINT "ATTENDI. . . "
220 GOTO 250
250 OPEN 15, 8, 15:OPEN 2, 8, 2, "AGENDA, L, "+CHR$(30)
255 X=0:J=0:I=1
260 PRINT#15, "P"CHR$(2)CHR$(I)CHR$(J)CHR$(X) :REM I=BYTE BASSO RECORD,
261 REM J=BYTE ALTO RECORD, X=POSIZIONE NEL RECORD
265 GOTO 300
270 CLOSE 2:CLOSE 15:PRINT "OPERAZIONE ESEGUITA. PREMI UN TASTO"
275 GET B$:IF B$="" THEN 275
280 GOTO 10
295 REM ROUTINE PER CERCARE UN NOME
300 GET#2, B$:IF ASC(B$+CHR$(0))=255 THEN GOTO 270
305 S$=S$+B$ :REM SE RECORD NON VUOTO, CERCA
310 IF LEN(S$)10 THEN 300 :REM RIPETE IL CICLO FINO A NOME COMPLETO
315 IF N$LEFT$(S$, LEN(N$)) THEN 330 :REM RECORD NON TROVATO, PROSEGUE
320 IF A$="2" THEN 350 :REM CANCELLA NOME
325 GOTO 375 :REM RICERCA NOME
330 S$="":X=0:I=I+1 :REM CAMBIA RECORD
335 IF I256 THEN 260
340 I=0:J=J+1:GOTO 260 :RECORD MAGGIORE DI 255, CAMBIA BYTE ALTO
345 REM ROUTINE DI CANCELLAZIONE DEL/I RECORD
350 X=0:PRINT#15, "P"CHR$(2)CHR$(I)CHR$(J)CHR$(1)
355 PRINT#2, CHR$(255);
360 S$="":GOTO 330
370 REM ROUTINE DI STAMPA DEL/I RECORD
375 K=0:PRINT S$;
380 GET#2, B$:PRINT B$;
385 IF B$=CHR$(13) THEN K=K+1
390 IF K2 THEN 380 :REM STAMPA FINO AL SECONDO RITORNO DI CARRELLO
395 S$="":GOTO 330
400 SYS 42100 :REM RITORNA ALL'INTERPRETE BASIC

Per comprendere questo programma dimostrativo è necessario conoscere la struttura dei file relativi. Quando si crea un file relativo, il 1541 scrive sul disco il nome del file ( come per qualsiasi altro file ) e crea un blocco dati, così composto:

  • i primi 2 byte indicano rispettivamente la traccia e il settore del successivo blocco dati su disco; se il primo byte è 0, il file non usa altri blocchi dati, e il secondo byte del blocco indica semplicemente il numero di byte utili (cioè atti a contenere dati) nel blocco.
  • i restanti 254 byte sono utilizzati dai record; il primo byte di ogni record è contrassegnato dal byte 255 ( FF in esadecimale ) e indica l'inizio di un record vuoto; il resto del record è costituito da byte 0 (00 in esadecimale).

Nel listato viene sfruttato questo principio per capire se il record è già occupato da dati (e quindi può essere scritto) oppure no.  Infine, il 1541 crea un blocco detto di SIDE SECTOR, che serve a creare i riferimenti per i diversi blocchi dati usati dal file relativo. Il side sector si rivela di vitale importanza per poter scrivere i dati di un record a cavallo tra un blocco e l'altro.

Bene, con questi brevi ma incisivi esempi di listati Basic spero di aver 'stuzzicato' qualcuno di voi nell'approfondire l'argomento programmazione del drive. A scopo didattico, puo' essere utile salvare questi programmi, sperimentari e provare a migliorarli.

Commenti
Commenta gioco C'è 1 commento per questo articolo. Registrati se vuoi lasciarne uno.
Questo articolo è scritto in modo semplice, chiaro e ordinato, preciso e approfondito, con spiegazioni dettagliate per ogni riga dei programmi presentati. Ho trovato questo articolo molto utile.
# - postato da Giovanni Giulio - 20 December 2007 [09:34]
Commodore 64
Pannello Utente
265 Visitatori, 4 Utenti
Phobos, Lordfener75, Pac76, Roberto
Ciao, ospite!
(Login | Registrati)
Merchandising
Ultimo Commento
Clicca per leggere tutti i commenti
Aquanaut
Se non fosse per il titolo "aqua" e il vedere perlomeno nelle prime schermate la superficie della stessa sembrerebbe più di guidare un'astronave in uno spazio / caverne aperte sullo stile di Fort Apocalypse che non un gioco ambientato ...
leggi »
Andy/AEG
Articolo
Intervista a Luciano Merighi (Merifon)
Ottimo articolo… solo una nota all’Autore dell’articolo… tra i programmatori bolognesi “pionieri” c’ero anche io: Andrea Paselli! Con Luca Zarri e Marco Corazza ho realizzato Chuck Rock, Over The Net, Mystere, Halley Adventure… ...
Andrea Paselli
Superlink