Abstrakt: Dokument popisuje jak připojit externí disk s rozhraním IDE případně paměťovou kartu Compact Flash k FITkitu a dále způsob komunikace přes rozhraní IDE.
K připojení standardního disku IDE se používá konektor, který obsahuje 40 pinů. Stejné rozhraní je možné bezezměny využít i ke komunikaci s paměťovou kartou Compact Flash (CF). Význam a umístění jednotlivých pinů je uvedeno v následující tabulce. Symbol -
u některých signálů značí jejich aktivitu v log. 0. Ke komunikaci se používá úroveň signálů TTL a pro FITKit tedy není zapotřebí nic měnit. Následující popis vychází ze specifikace ATA-3, která by měla být v dnešní době podporována téměř všemi pevnými disky.
Signál |
I/O |
číslo pinu |
Signál |
I/O |
číslo pinu |
RESET- |
I |
1 |
Zem |
|
2 |
DD7 |
I/O |
3 |
DD8 |
I/O |
4 |
DD6 |
I/O |
5 |
DD9 |
I/O |
6 |
DD5 |
I/O |
7 |
DD10 |
I/O |
8 |
DD4 |
I/O |
9 |
DD11 |
I/O |
10 |
DD3 |
I/O |
11 |
DD12 |
I/O |
12 |
DD2 |
I/O |
13 |
DD13 |
I/O |
14 |
DD1 |
I/O |
15 |
DD14 |
I/O |
16 |
DD0 |
I/O |
17 |
DD15 |
I/O |
18 |
Zem |
|
19 |
klíč |
|
20 |
DMARQ |
O |
21 |
Zem |
|
22 |
DIOW- |
I |
23 |
Zem |
|
24 |
DIOR- |
I |
25 |
Zem |
|
26 |
IORDY |
O |
27 |
CSEL |
|
28 |
DMACK- |
I |
29 |
Zem |
|
30 |
INTRQ |
O |
31 |
Rezervováno |
|
32 |
DA1 |
I |
33 |
PDIAG- |
|
34 |
DA0 |
I |
35 |
DA2 |
I |
36 |
CS0- |
I |
37 |
CS1- |
I |
38 |
DASP- |
|
39 |
Zem |
|
40 |
Tabulka : Popis jednotlivých pinů konektoru (I=disk pouze čte, O=disk pouze zapisuje, I/O=obousměrný)
Jednotlivé piny mají následující význam:
RESET- : Hardwarový reset (inicializace). Po inicializaci disky provedou diagnostiku.
DD0-DD15 : Obousměrné datové vodiče. Přenos dat probíhá po 16-ti bitech, přístup k registrům po 8-mi bitech (signály DD0-DD7).
klíč : Tento pin bývá odstraněn a měl by zabránit špatnému otočení kabelu
DMARQ : Disk signalizuje, že může přenést jedno slovo dat v DMA režimu
DMACK- : Tímto signálem signalizuje řadič disku platnost dat v DMA režimu
DIOW- : Tento signál signalizuje zápis dat na disk (použit ve všech režimech)
DIOR- : Tento signál signalizuje čtení dat z disku (použit ve všech režimech)
IORDY : Signalizace disku, že je připraven na další přenos dat (jen PIO režim). Je nutný jen v PIO módech 2 a výš, v nižších je pouze volitelný
INTRQ : Signalizuje dokončení operace, je vypínatelný
DA0, DA1, DA2, CS0-, CS1- : tyto signály slouží k adresaci registru (viz Tabulka 2)
CSEL : Umožňuje konfiguraci disků podle umístění na kabelu
DASP-,PDIAG : Jsou použity disky k diagnostice a vzájemné identifikaci
Disk může v dnešní době pracovat v několika režimech, lišících se víceméně přenosovou rychlostí. Nejjednodušším je přenos dat v PIO režimu, kdy jsou využity signály DD0-DD15, DA0-DA2, CS0-, CS1-, DIOW- a DIOR-. Komplikovanější avšak výkonnější DMA režim navíc vyžaduje obsluhu signálů DMARQ a DMACK-.
Je vhodné též využít signál RESET-, nebo jej trvale umístit do stavu log. 1. Signály INTRQ a IORDY mohou být použity volitelně. Ostatní signály by měly zůstat nezapojené.
FITkit je připojen k IDE přes standartní 40-pinový kabel, pro FITkit verze 1.x musí být konekor upraven obroušením jeho okrajů, aby nezavazel pinům konektoru, FITKit 2.0 má jiné umístění konektoru (nevyžaduje jeho úpravu). FITKit 2.0 ale nemá připraven žádný typ architektury.
Použitý řadič umožňuje několik poloh kabelu, o zapojení vývodů se stará komponenta IDE_port. Tato komponenta se nachází v adresáři fpga\ctrls\ide
.
Popis portů komponenty:
X: 46-bitový port, slouží pro přímé napojení na port X FPGA komponenty (konektor)
IDE: 26-bitový port, napojuje se na port IDE řadiče, obsahuje všechny nutné signály
Komponenta má několik architektur, které jsou přizpůsobeny poloze konektoru:
Architektura basic: Je určena pro standartní polohu kabelu, viz obrázek
Architektura rotate: Je určena pro obrácenou polohu kabelu, vhodné pro umístění FITKitu na disk - zabraňuje přetočení kabelu
Architektura small: Je určena pro minimální využití portu X, umožňuje použití standartních komponent, vhodné ve spojení s architekturou čipu IDE (port X je přítomen zároveň se standartními porty). Pro tuto variantu je však potřeba speciálně upravit kabel a konektor se umísťuje jinak, aby se využily piny se zemí.
Je potřeba přepojit několik vodičů - lze využít samotný konektor, neboť obsahuje samořezná upínací místa. Při návrhu se předpokládalo přehnutí vývodů 33-40 ke kabelu, což umožňuje snížení rozdílu v délce původních a přepojených vodičů. Nadstavovat je nutné pouze vývod č. 1. Tabulka 2 ukazuje seznam vývodů a jejich přepojení. Je vhodné (ale ne nutné) pospojovat vodiče, označené "Na společnou zem" a připojit je na vývody 1 a 2.
Vodič |
Úprava |
Připojit vodič |
Vodič |
Úprava |
1 |
Přepojit na 19 |
Společná zem |
29 |
Beze změny |
2 |
Zem |
|
30 |
Na společnou zem |
3-18 |
Beze změny |
|
31 |
Zrušit |
19 |
Na společnou zem |
1 |
32 |
Zrušit |
20 |
Zrušit |
38 |
33 |
Přepojit na 27 |
21 |
Beze změny |
|
34 |
Zrušit |
22 |
Na společnou zem |
37 |
35 |
Přepojit na 26 |
23 |
Beze změny |
|
36 |
Přepojit na 24 |
24 |
Na společnou zem |
36 |
37 |
Přepojit na 22 |
25 |
Beze změny |
|
38 |
Přepojit na 20 |
26 |
Na společnou zem |
35 |
39 |
Zrušit |
27 |
Zrušit |
33 |
40 |
Na společnou zem |
28 |
Zrušit |
|
|
|
Tabulka : Tabulka 2: Přepojení pinů na konektoru
Komunikace probíhá prostřednictvím zápisu/čtení do/z řídících/datových registrů. Jednotlivé registry a jejich adresy jsou uvedeny v následující tabulce (hodnoty signálů CS1- a CS0- jsou konečné, tedy po invertování).
Adresa Význam při čtecí a zápisové operaci |
||||||
CS1- |
CS0- |
DA2 |
DA1 |
DA0 |
čtení |
zápis |
1 |
1 |
0 |
0 |
0 |
klidový stav + DMA přenos |
|
1 |
0 |
1 |
1 |
0 |
alternativní status + řízení zařízení |
|
0 |
1 |
0 |
0 |
0 |
přenos dat (PIO) |
|
0 |
1 |
0 |
0 |
1 |
chybový registr |
funkce |
0 |
1 |
0 |
1 |
0 |
počet sektorů |
|
0 |
1 |
0 |
1 |
1 |
LBA(7-0) |
|
0 |
1 |
1 |
0 |
0 |
LBA(15-8) |
|
0 |
1 |
1 |
0 |
1 |
LBA(23-16) |
|
0 |
1 |
1 |
1 |
0 |
LBA(27-24) + výběr disku |
|
0 |
1 |
1 |
1 |
1 |
status |
příkaz |
Tabulka : Tabulka 3: Adresy jednotlivých registrů
Popis registrů
klidový stav + DMA přenos: Tato kombinace adresních bitů definuje klidový stav a je používána v případě DMA přenosu, kdy je nutné nastavit tuto adresu, což umožňuje přerušit probíhající DMA přenos
alternativní status : vrací stejné výsledky, jako registr status, ale neruší stav chyby.
řízení zařízení : bit 1 = vypnutí přerušení (0=přerušení zapnuto), bit 2 = softwarový reset
chybový registr : pokuď je nastaven bit 0 v registrech status/alternativní status, vrací seznam chyb:
bit 7 |
bit 6 |
bit 5 |
bit 4 |
bit 3 |
bit 2 |
bit 1 |
bit 0 |
r |
UNC |
MC |
IDNF |
MCR |
ABRT |
TK0NF |
AMNF |
Tabulka : přiřazení jednotlivých bitů chybového registru
Význam bitů chybového registru:
AMNF: adresa nebyla nalezena i po nalezení správného ID sektoru
TK0NF: stopa číslo 0 nenalezena
ABRT: příkaz přerušen (neznámý příkaz, nebo nastala chyba)
MCR: žádost o změnu média (pouze u vyměnitelných médií)
IDNF: sektor nenalezen
MC: médium změněno (pouze u vyměnitelných médií)
UNC: neopravitelná data (při zápisu/čtení)
r: rezervován
status registr/alternativní status : vrací stav média, čtení tohoto registru ruší chybové stavy
bit 7 |
bit 6 |
bit 5 |
bit 4 |
bit 3 |
bit 2 |
bit 1 |
bit 0 |
BSY |
DRDY |
DF |
DSC |
DRQ |
CORR |
IDX |
ERR |
Tabulka : přiřazení jednotlivých bitů stavového registru
Význam bitů stavového registru:
ERR: nalezena chyba, popis chyby je v chybovém registru
IDX: záleží na výrobci
CORR: nalezena opravitelná data, přenos dat je nepřerušen
DRQ: žádost o data - disk je připraven přenášet data
DSC: stopa nalezena
DF: chyba zařízení - porucha disku
DRDY: zařízení připraveno
BSY: zařízení zaneprázdněno - nepřijímá další příkazy
funkce: slouží pro zapsání dodatečných parametrů pro některé příkazy
počet sektorů: určuje počet přenášených sektorů naráz, 0 = 256
LBA(23-0): adresa sektoru v režimu LBA28
LBA(27-24) + výběr disku: nejvyšší 4 bity adresy, bity 7 a 5 mají být nastaveny na 1, bit 6 je nastaven na 1 pro LBA režim, bit 4 určuje vybraný disk (0=MASTER)
příkaz: provedení příkazu disku, příkaz se spouští zápisem kódu na tento registr (všechny potřebné hodnoty už musejí být nastaveny)
Přenosové režimy
V režimu PIO je celý přenos v režii řadiče komunikujícího s diskem. Veškeré doby jsou uvedeny pro rychlost PIO 0. Přenos znaku (v případě registru) nebo slova (jsou-li přenášena data) musí být vždy zahájen nastavením správné adresy (CS1-, CS0-, DA2-DA0) -viz Tabulka 3. Po ustalovací době adresních bitů (min. 70ns) může být aktivován signál DIOW- v případě jedná-li se o zápis nebo signál DIOR- v případě čtení. Vybraný signál musí být nastaven min. po dobu 290ns. Při zápisu dat musí být na datových vodičích data přítomna min. 60ns před daktivací signálu DIOW- a min. 30ns po jeho deaktivaci. Čtená data jsou platná min. 50ns před deaktivací signálu DIOR-. Minimální délka cyklu je 600ns.
V režimu DMA je přenos řízen diskem. Během přenosu musí řadič nastavit neutrální adresu (signály CS0- a CS1- jsou na 1 po zinvetování). Veškeré doby jsou uvedeny pro rychlosti DMA0/DMA1. Přenos zahajuje disk nastavenim signálu DMARQ, pokuď řadič může data zpracovat či je dodat, tak nastaví signál DMAACK. Poté vždy řadič nastaví signál DIOR-/DIOW- podle směru dat (nastaveny musejí být min. po dobu 215ns/80ns), data musejí být nastavena diskem/řadičem (čtení/zápis na disk) min. 100ns/30ns před zrušením těchto signálů. Při zápisu musí řadič data na výstupu podržet min. 20ns/15ns po ukončení DIOW-. Disk může zrušit signál DMARQ nejpozději 120ns/40ns po nastavení signálů DIOR-/DIOW-. Minimální doba mezi náběžnými hranami signálů DIOW-/DIOR- je 480ns/150ns, což určuje max. přenosovou rychlost.
Příkazy se provedou zapsáním potřebných hodnot do registrů a pak zapsáním čísla příkazu do registru příkaz.
Seznam příkazů a jejich číselných kódů:
Příkazy čtení/zápisu:
PIO čtení 0x21
PIO čtení s návratem 0x20
PIO zápis 0x31
PIO zápis s návratem 0x30
DMA čtení 0xC9
DMA čtení s návratem 0xC8
DMA zápis 0xCB
DMA zápis s návratem 0xCA
vstupy:
adresa prvního sektoru a číslo disku v registrech LBA(23-0) (předpokládáme vždy režim LBA).
počet sektorů (1-256) ke čtení/zápisu v registru počet sektorů
popis:
zahájení čtení/zápisu v PIO/DMA režimu a příp. s návratem (opakování čtení špatně načtených registrů).
data jsou přítomna při nastavení stavu DRQ ve status registru
ve specifikaci ATA 3 musí být přítomny všechny typy těchto příkazů, ale používány by měly být spíše typy s návratem (na testovaném disku verze bez návratu nepracovala tak, jak měla)
Příkazy identifikace disku
Identifikace PIO 0xEC
Identifikace DMA 0xEE
popis:
přenos 1 sektoru (512B dat) z disku, obsahující informace aktuální o disku. Verze DMA je ve specifikaci ATA3 pouze dobrovolná (je tedy nutné počítat i s PIO verzí)
některé (nejpoužívanější) položky (pro úplný seznam viz specifikace ATA):
Offset |
Velikost [B] |
Popis |
14H |
20 |
Sériové číslo disku (opačné pořadí znaků a znaky vyplněny do konce mezerami) |
36H |
40 |
Model disku (jako u sériového čísla) |
78H |
4 |
počet adresovatelných sektorů (pouze LBA) |
7EH |
2 |
bity 15-8 - aktivní DMA režim, bity 7-0 - podporovaný DMA režim |
A0H |
2 |
bity 15-1 podporovaná specifikace ATA (bit 1=ATA1, ...) |
Tabulka : Některé položky identifikace disku
Příkaz nastavení vlastností disku:
Nastav vlastnosti 0xEF
vstupy:
registr funkcí obsahuje číslo podpříkazu
další registry podle jednotlivých podpříkazů
popis:
nastaví některou z vlastností, může například nastavovat vyrovnávací paměť, spotřebu disku, či režim přenosu
režim přenosu: podpříkaz 03H, hodnota se nastavuje do registru počtu sektorů. Typ režimu je vybrán horními 5 bity, spodní 3 bity určují hodnotu.
Horních 5 bitů |
Dolní 3 bity |
Popis |
00000 |
000 |
Základní PIO režim |
00000 |
001 |
Základní PIO režim (bez řízení s IORDY) |
00001 |
nnn |
PIO režim nnn |
00100 |
nnn |
DMA režim nnn |
Tabulka : Nastavení přenosového režimu
Další příkazy (viz specifikace ATA):
příkazy pro přenášení skupin sektorů (čtení/zápis, PIO/DMA)
příkazy pro verifikaci zápisu/čtení
příkazy pro řízení stavu disku (spotřeby)
příkazy SMART
příkazy zabezpečení dat
Specifikace ATA2: http://www.t13.org/Documents/UploadedDocuments/project/d0948r4c-ATA-2.pdf
Specifikace ATA3: http://www.t13.org/Documents/UploadedDocuments/project/d2008r7b-ATA-3.pdf
Tabulka MBR se nachází v sektoru 0 a popisuje jednotlivé oddíly, nacházející se na disku. Na začátku sektoru se nachází 446B spustitelného kódu. Za touto oblastí se nachází čtyři 16-bytové popisy jednotlivých oddílů. Sektor je uzavřen znakem AA55H, který označuje MBR sektor. Jednotlivé popisy mají strukturu, uvedenou v tabulce 5.
Offset |
Velikost [B] |
Popis |
00H |
1 |
Stav(0 = neaktivní, 80H = aktivní) |
01H |
1 |
Začátek – číslo hlavy |
02H |
2 |
Začátek – cylindr/sektor |
04H |
1 |
Typ oddílu (tabulka 6) |
05H |
1 |
Konec – číslo hlavy |
06H |
2 |
Konec – cylindr/sektor |
08H |
4 |
Logické číslo počátečního sektoru |
0CH |
4 |
Počet sektorů oddílu |
Tabulka : Tabulka 5: Popis položky MBR
Typ |
Popis |
00H |
Neznámý/žádný |
01H |
FAT12 |
04H |
FAT16 (menší než 32MB) |
05H |
Rozšířený oddíl DOS |
06H |
FAT16 (větší než 32MB) |
0BH |
FAT32 |
0CH |
FAT32 s LBA rozšířením (služby 13H BIOS) |
0EH |
FAT16 s LBA |
0FH |
Rozšířený oddíl DOS s LBA |
Tabulka : Tabulka 6: Typy souborových systémů
Rozšířený oddíl DOS umožňuje větší počet oddílů na disku, než jsou základní čtyři. Ukazuje na strukturu, podobnou MBR, která obsahuje popis dalšího oddílu FAT a případně odkaz na další rozšířený oddíl. Adresa je ovšem vztažena k pozici aktuální tabulky, je tedy nutné je sečíst. Poslední rozšířený oddíl obsahuje již pouze poslední oddíl FAT.
Podrobněji bude popisován systém FAT32, ostatní systémy pouze okrajově. První sektor oddílu FAT je Boot Record (viz tabulka 7). Obsahuje všechny potřebné údaje ke správnému nastavení oddílu.
Offset |
Velikost [B] |
Popis |
Jméno |
00H |
3 |
Adresa spustitelné oblasti |
JumpCode |
03H |
8 |
Jméno systému, který oddíl vytvářel |
OEMName |
0BH |
2 |
Počet bytů na sektor (512,1024,2048,4096) |
BytsPerSec |
0DH |
1 |
Sektorů na cluster |
SecPerClus |
0EH |
2 |
Rezervovaných sektorů (běžně 32) |
RsvdSecCnt |
10H |
1 |
Počet FAT tabulek (běžně 2) |
NumFATs |
11H |
2 |
Počet položek v Root Directory (pro FAT32=0) |
RootEntCnt |
13H |
2 |
Celkový počet sektorů.=0: údaj je ve 32b v. |
TotSec16 |
15H |
1 |
Typ disku, = F8H: pevný |
Media |
16H |
2 |
Počet sektorů na FAT t.=0: údaj je ve 32b v. |
FATSz16 |
18H |
2 |
Sektorů na stopu |
SecPerTrck |
1AH |
2 |
Počet hlaviček |
NumHeads |
1CH |
4 |
Počet skrytých sektorů |
HiddSec |
20H |
4 |
Celkový počet sektorů.=0: údaj je ve 16b v. |
TotSec32 |
24H |
4 |
Počet sektorů na FAT t.=0: údaj je ve 16b v. |
FATSz32 |
28H |
2 |
Aktivita FAT tabulek, bit 7 = 1: pouze jedna aktivní FAT tabulka (její číslo v bitech 0-3), = 0: mirroring| |
ExtFlags |
2AH |
2 |
Verze FAT, měla by být = 0 |
FSVer |
2CH |
4 |
Číslo clusteru kořenového adresáře |
RootClus |
30H |
2 |
Číslo informačního sektoru (obvykle 1) |
FSInfo |
32H |
2 |
Číslo záložního boot sektoru |
BkBootSec |
34H |
12 |
Rezervováno |
|
40H |
1 |
Písmeno disku, pevné disky začínají od 80H |
DrvNum |
41H |
1 |
Rezervováno |
|
42H |
1 |
Následující 3 položky jsou přítomné: |
BootSig |
43H |
4 |
Číslo svazku, pro identifikaci |
VolID |
47H |
11 |
Jméno svazku |
VolLab |
52H |
8 |
Typ systému, obvykle "FAT32 " |
FilSysType |
Tabulka : Tabulka 7: Boot Record
Informační struktura, pokud se nachází na oddílu (FSInfo>0), obsahuje některé informativní údaje. Tyto údaje jsou pouze informativní a nemusejí být správné.
Offset |
Velikost [B] |
Popis |
1E8H |
4 |
Počet volných clusterů, = -1: neznámý |
1ECH |
4 |
Číslo clusteru, který byl naposledy alokován (zrychlení vyhledávání) |
Tabulka : Tabulka 8: Informační struktura
RootDir = [(RootEntCnt * 32) + BytsPerSec - 1]/BytsPerSec
ClusStart = (NumFATs * FATSize) + RsvdSecCnt + RootDir
Clusters = (Sectors - ClussStart) / SecPerClus
Typ FAT tabulky by měl být určen právě z počtu clusterů, nikoliv tedy ze jména svazku (FilSysType) nebo jiných typických znaků. Pokud je počet clusterů menší než 4085, jedná se o FAT12, je-li větší nebo roven 4085 a menší, než 65525, jedná se o FAT16 a je-li větší nebo roven 65525, jedná se o FAT32. Číslo sektoru, na kterém se nachází cluster, lze spočítat: Sector = (Cluster-2)*SecPerClus + ClusStart
Adresáře jsou podobné souborům, liší se pouze svojí délkou (adresáře mají vždy nulovou délku) a atributem DIRECTORY. Přístup k nim je však podobný. Adresář obsahuje jednotlivé položky, dlouhé 32B, které popisuje tabulka 9. Položky jsou řazeny za sebou a konec adresáře je označen zarážkou. Kořenový adresář se ve FAT32 nachází na clusteru č. RootClus.
Offset |
Velikost [B] |
Popis |
Jméno |
00H |
8 |
Jméno položky, prázdná místa vyplněna znakem 32 |
Name |
08H |
3 |
Koncovka p., prázdná místa vyplněna znakem 32 |
Ext |
0BH |
1 |
Atributy položky |
Attr |
0CH |
1 |
Rezervováno |
NTRes |
0DH |
1 |
Čas vytvoření – setiny sekundy (pro 2 sekundy) |
CrtTimeTenth |
0EH |
2 |
Čas vytvoření – granularita jsou 2 sekundy |
CrtTime |
10H |
2 |
Datum vytvoření |
CrtDate |
12H |
2 |
Datum posledního čtení/zápisu |
LstAccDate |
14H |
2 |
Číslo prvního clusteru (horní polovina) |
FstClusH |
16H |
2 |
Čas poslední změny (včetně vytvoření souboru) |
WrtTime |
18H |
2 |
Datum poslední změny (včetně vytvoření souboru) |
WrtDate |
1AH |
2 |
Číslo prvního clusteru (dolní polovina) |
FstClusL |
1CH |
4 |
Délka souboru |
FileSize |
Tabulka : Tabulka 9: Položka adresáře
Typ položky je určen prvním znakem jména:
E5H – volná položka
05H – normální položka, první znak = E5H
00H – prázdná položka, za ní se nenachází žádná jiná položka (zarážka)
jiná hodnota – normální položka
CrtDate, LstAccDate, WrtDate |
CrtTime, WrtTime |
||||
Rok |
Měsíc |
Den |
Hodiny |
Minuty |
Vteřiny |
(Bity 15 – 9) |
1980|Bity 8 – 5 |
Bity 4 – 0 |
Bity 15 – 11 |
Bity 10 – 5 |
(Bity 4 – 0) * 2 |
Tabulka : Formát datumu a času
Atributy položky (kromě dlouhého jména jsou všechny komutativní):
01H: Pouze pro čtení
02H: Skrytý soubor/adresář
04H: Systémový soubor/adresář
08H: Jméno svazku (smí být pouze v kořenovém adresáři)
10H: Adresář
20H: Archivní soubor/adresář (byl změněn)
0FH: Dlouhé jméno
Pokud má nějaká položka dlouhé jméno, je toto uloženo v položkách jí předcházejících a s atributem "Dlouhé jméno". Každá taková položka obsahuje 13 znaků v kódování UTF16 a popisuje ji tabulka 10.
Offset |
Velikost [B] |
Popis |
Jméno |
00H |
1 |
Pořadové číslo záznamu |
SequenceNumber |
01H |
10 |
5 znaků jména |
Name1 |
0BH |
1 |
Atribut = 0FH |
Attr |
0CH |
1 |
Rezervováno |
Type |
0DH |
1 |
Kontrolní součet |
CheckSum |
0EH |
12 |
6 znaků jména |
Name2 |
1AH |
2 |
Musí být 0 |
FirstClusterLO |
1CH |
6 |
3 znaky jména |
Name3 |
Tabulka : Tabulka 9: Položka adresáře
Položky jsou řazeny v opačném pořadí (od konce jména po jeho začátek), pořadové číslo je od N po 1, položka s číslem N má k tomuto číslu přičteno ještě 40H.
FAT tabulky se nacházejí za oblastí rezervovaných sektorů. První sektor tabulky (FATNum) se dá vypočítat pomocí vztahu: FATSector = RsvdSecCnt + FATNum * FATSz Pro FAT32 je tabulka tvořena polem položek o velikosti 4B, z nichž je použito 28bitů, nejvyšší 4bity jsou rezervovány a neměly by se měnit. Pro velikost sektoru 512B (nejpoužívanější) se tedy v jednom sektoru nachází 128 položek. Každá položka obsahuje číslo následujícího clusteru souboru/adresáře. Hodnota větší nebo rovna 0FFFFFF8H znamená konec řetězce, řetězec dále již nepokračuje a aktuální cluster je poslední. Číslo prvního clusteru řetězu je uloženo v položce adresáře ve FstClusL a FstClusH. Soubor o nulové délce, který dosud nemá alokována data, má číslo 0. Hodnota 0FFFFFF7H znamená vadný cluster. Hodnota 0 označuje volný cluster. Clustery číslo 0 a 1 nesmějí být použity.
Na obrázku je ukázka tabulky FAT (v tomto případě FAT32) s velikostí 2KB na cluster. Kořenový adresář má přidělených 5 clusterů (2,3,4,7,5) a obsahuje 3 položky (zbytek místa by měl být vynulován, nulová položka je poslední položkou v adresáři).
První položka obsahuje soubor PRVNI.NIC (název by měl být psán velkými písmeny, FAT je necitlivá na velikost písmen). Ten však nemá ještě přiděleno místo, neboť jej dosud nepotřeboval, a tak má jako počáteční cluster hodnotu 0.
Druhá položka byla smazána, avšak předtím měla přidělena cluster číslo 5 (a pravděpodobně i 6, což vysvětluje skok v řetězci adresáře).
Třetí položka má přiděleny 4 clustery (8,9,10,11), aby mohla obsahovat všech 7654B dat.
Použitý řadič se skládá z několika bloků a využívá komunikace přes rozhraní SPI. Zdrojové kódy se nacházejí v adresáři fpga\ctrls\ide
, přičemž jsou k dispozici tři verze podle toho, zda má být přítomen kanál pro přímý přenos dat do jiných zařízení na FPGA.
Popis signálů
IDE: 26b port, určený pro připojení na komponentu ide_port
RST: reset řadiče
CLK: hodiny
DI, DI_REQ, DO, DO_VLD, CS: signály rozhraní SPI
INTRQ: plánován pro přerušení, není využit a u varianty s výstupním kanálem ani není přítomen
READ_EN: řadič má připravena data pro zařízení
WRITE_EN: řadič vyžaduje data ze zařízení
DATA_IN: vstupní data do řadiče (8b)
DATA_OUT: výstupní data ze řadiče (8b)
ACCEPT: potvrzení platnosti dat (v obou směrech) zařízením
Základním blokem je obvod zápisu/čtení v PIO režimu, neboť ten je nutný pro přístup k registrům a taktéž umožňuje 16-bitový přenos dat - především využito identifikací disku, u které je DMA verze pouze volitelná. tento režim využívá port na adresách 0300H – 033EH, bity 5-1 adresy určují adresu registru. Přístup je vždy 16-bitový. Na adrese 04H se nachází řídící registr (8-bitový) signálu RESET-, ten je řízen bitem 0.
Další blok je určen pouze k hromadnému zápisu registrů s rostoucí adresou, což umožňuje především rychlejší zadání počtu sektorů, adresy sektoru a provedení příkazu (v tomto pořadí adresy rostou). Tento blok využívá adresy 0000H-001FH, kde bity 4-0 určují adresu prvního registru.
Přenos dat má nastarosti řadič DMA, který obsahuje jednu paměť BRAM, která se svojí velikostí 2kB umožňuje uchovávat až 4 sektory v paměti. Umístění dat v této paměti umožňuje především náhodný přístup k datům a odlehčení paměti procesoru v případě zápisu dat. Také konvertuje 16b data na 8b. Přístup k datům se provádí registrem na adesách 0800H-0FFFH, kde spodních 11 bitů určuje adresu 1. přenášeného znaku (horní 2 bity určují sektor). Přenos dat je 8b a umožňuje blokový přenos dat s inkrementální adresou. Přenos je řízen registrem na adrese 05H (8b registr), kde jednotlivé bity mají význam:
Zápis: bit 7 - spouští DMA přenos, bit 6 – provádí RESET obvodu, bit 5 – rychlost DMA (0=DMA0, 1=DMA1), bit 4 směr dat (0=čtení z disku, 1=zápis), bity 0-1 – výběr oblasti BRAM
Čtení: bit 7 – řadič stále pracuje
Reset obvodu je vhodné provést zvlášť před spuštěním a také před provedením příkazu na disku. Bity 1 a 0 určují jeden ze 4 cílových bloků paměti, přenáší se vždy všech 512 znaků.
Poslední blok je volitelný (výběrem typu řadiče) a je určen pro přenášení dat mezi pamětí řadiče a jiným zařízením na FPGA. Přenos je řízen řadičem a je 8bitový. Během přenosu je blokován přístup k datům, na stav přenosu se lze dotázat, ale pokud komunikující obvod příliž nezdržuje, mohu být data přenesena dříve, než je dotaz proveden. Zároveň může být přeneseno všech 2048 znaků. Řídící registr (24b) je na adresách 10H-11H:
Zápis: bit 23 – spouští obvod, bit 22 určuje směr dat (0=z obvodu), bity 21-11 jsou cílová adresa, bity 10-0 pak počáteční adresa
Čtení: bit 23 – obvod běží, bity 21-11 jsou cílová adresa, bity 10-0 pak aktuální adresa
Pokud chce řadič data číst z/zapisovat do vnitřní paměti BRAM, vystaví signál READ_EN / WRITE_EN a zapíše data na DATA_OUT /čte data z DATA_IN. Komunikující zařízení potvrzuje data signálem ACCEPT.
Celkový přehled portů je v tabulce 4.
adresa |
režim |
použití |
délka adresy (B) |
délka dat(B) |
00H |
Z |
hromadný přístup k registrům disku |
2 |
1+ |
03H |
Z/Č |
zápis/čtení PIO režim |
2 |
2 |
04H |
Z |
řízení hardwarového resetu |
1 |
1 |
05H |
Z/Č |
řízení/stav DMA kanálu |
1 |
1 |
08H-0FH |
Z/Č |
čtení/zápis dat z sektorové paměti |
2 |
1+ |
10H-11H |
Z/Č |
řízení/stav výstupního kanálu |
1 |
3 |
Tabulka : Tabulka 4: přehled portů řadiče
K usnadnění práce s diskem byly vytvořeny dvě jednotky a sice ide.h
a fat.h
.
Tato jednotka je určena pro zastřešení práce s řadičem pevných disků. Jejím úkolem je identifikace disku/disků, načítání/ukládání dat, správa paměti na řadiči a případně ovládání výstupního kanálu. V hlavičkovém souboru se nachází mnoho konstant pro adresy portů, jejich hodnoty, ale i seznam všech příkazů disku. Vzhledem k nejasnostem při identifikaci disků je jednotka schopná identifikovat pouze disku typu MASTER, i když je stavěná pro práci na 2 discích.
Popis funkcí - základní funkce
Je třeba provést před hledáním disku
vyhledává disk/disky, dokud je třeba hledat, tak vrací IDE_SETUP_WAIT
nastaví dobu čekaní na operace, základní hodnota je 16000
do 512B bufferu v paměti zapíše data z identify (používá PIO režim), vrací IDE_RET_OK v případě úspěchu
provede hardwarový reset
inicializuje vnitřní paměť řadiče, nastaví ji na základní hodnoty. Vhodné ji provést po nalezení disků a před přístupem na disk
nastaví operační oblast jedné ze 4 oblastí v paměti. Oblast cache teď bude použita pro sektory Ssector až Esector disku disk. Určena pro optimalizaci přístupu.
Vyprázdní vybranou cache – pokud obsahuje nezapsaná data, jsou zapsána na disk
nastaví aktuální disk a sektor, vrací stav, (IDE_C_OK v případě úspěchu)
zapíše count dat na aktuální sektor od pozice offset, count+offset<=512. Pokud data==NULL, zapisuje data z výstupního kanálu. Vrací počet zapsaných bytů
přečte count dat z aktuálního sektoru od pozice offset, count+offset<=512. Pokud data==NULL, zapisuje data na výstupní kanál. Vrací počet přečtených bytů
upravuje řetězec z identify na ANSI formu, cílová oblast musí být alepsoň len+1 velká. Znaky jsou totiž přeházeny a zbytek řetězce je vyplněn znaky mezer
Popis funkcí - systémové funkce (málo využití mimo jednotku)
upravená funkce, určená pro data délky 3 - FPGA_SPI_RW_A8_DN zadává byty v opačném pořadí. V případě čtení vrací přečtená data.
zapisuje/čte count dat z/do cahce do/z výstupního kanálu
provede příkaz, testuje chybové stavy před a po, vrací IDE_RET_OK
přečte/zapíše data z/do cache
přečte/zapíše data z/do datového PIO registru
změní aktuální disk
změní aktuální sektor
změní aktuální sektor a provede příkaz
přečte/zapíše registr
čeká, až se nastaví status astatus a zruší status nstatus, nebo vyprší čas (count testů). Pokud errdetect!=0, pak při příznaku chyby skončí. Vhodný před některými příkazi, případně po nich
Tato jednotka slouží k přístupu na disky se souborovým systémem FAT32. Je možno ji upravit i na systémy FAT16 a FAT12, ale jejich použití se nepředpokládá.
Popis funkcí
prochází přítomné souborové systémy na disku disc. Pokud je fat==NULL, tak vrací počet přípustných souborových systémů, pokud ne, inicializuje part přípustný souborový systém (počítáno od 0). Pokud volume!=NULL, zapíše do něj jmenovku svazku (oblast velká alespoň 13 bytů, řetězec ve formátu ANSI)
uzavře použitou FAT – uloží údaj o volném místě a naposledy použitém clusteru, vhodné před ukončením práce po zápise na disk
do dir načte kořenový adresář FAT systému
započne hledání v adresáři dir položky jména name (lze použít hvězdičkovou/otazníkovou notaci)
hledá v adresáři dir položku se zadaným jménem, do Fname uloží jméno položky (min. 9B) a do ext pozici koncovky ve jméně (min. 4B). Do attr uloží atributy položky – je vhodné porovnávat na adresář/jmenovku svazku. Pokud file!=NULL, pak je do něj položka inicializována (lze číst, zapisovat, případně použít jako adresář pro hledání). Vrací FAT_OK, pokud nalezne další položku a FAT_EOF, pokud došel na konec adresáře
umožní pokračovat v hledání, položka name je stejná, jako u FAT_Set_Find. Může být použito pouze jedno hledání zároveň a některé funkce (FAT_Delete_File) také hledání přerušují. Potom je hledání nutné obnovit, neboť je hledané jméno globální proměnná
vytvoří soubor se jménem name a atributy attr v adresáři dir, pokud neexistuje, (nebo nemá nulovou délku). Délku lze vynulovat pomocí fce FAT_Clear. Datum a čas vytvoření je určen globálními proměnnými NEW_FILE_DATE a NEW_FILE_TIME. Funkce testuje platnost použitých znaků
vynuluje délku souboru a uvolní použité místo
vymaže soubor, přerušuje případné hledání souborů
uzavře soubor – aktualizuje délku souboru, zapíše nezapsaná data
přečte/zapíše length bytů z/do souboru. Pokud je buff==NULL, přenášejí se data přes výstupní kanál řadiče.
nastaví polohu v souboru na pozici pos. Pos je v intervalu<0;f->FileSize>. Od této pozice lze nadále zapisovat i číst
Datové typy (přehled užitečných vlastností:
tFAT: popis souborového systému
unsigned char FATType: typ FAT (například FAT_32)
unsigned long Clusters: celokvý pořet clusterů
unsigned long SecPerClus: počet sektorů/cluster
unsigned long FreeClus: počet volných clusterů, 0xffffffff = neznámo
tFile: popis souboru/adresáře
unsigned char attr: atributy
unsigned long Pos: aktuální pozice v souboru
unsigned long FileSize: velikost souboru (max. 2GB)
tFAT *fat: odkaz na FAT souboru
Konstanty atributů:
ATTR_READ_ONLY: pouze pro čtení
ATTR_HIDDEN: skrytý soubor
ATTR_SYSTEM: systémový soubor
ATTR_VOLUME_ID: identifikátor svazku, pouze v kořenovém adresáři
ATTR_DIRECTORY: adresář
ATTR_ARCHIVE: archivní soubor
ATTR_LONG_NAME: dlouhé jméno
Inicializace disku a 1. partition:
tFAT F; tFile ADir; char name[13]; void Init() { term_send_str("Inicializace IDE"); IDE_HDD_Setup_Init(); while (IDE_HDD_Setup() == IDE_SETUP_WAIT) { WDG_reset(); term_send_str("."); } term_send_crlf(); term_send_str("Disk: "); switch (IDE_HDD[0].status) { case IDE_HDD_UNKNOWN:term_send_str(" Neidentifikovan!");break; case IDE_HDD_NONE:term_send_str(" Neni");break; case IDE_HDD_BAD:term_send_str(" Vadny!");break; case IDE_HDD_ATA:term_send_str(" ATA");break; case IDE_HDD_ATAPI:term_send_str(" ATAPI");break; case IDE_HDD_ATA+IDE_HDD_SMART:term_send_str(" ATA + SMART");break; } term_send_crlf(); if (IDE_HDD[0].status >= IDE_HDD_ATA) { term_send_str(" Velikost: "); term_send_num(IDE_HDD[0].sectors >> 11); term_send_str_crlf(" MB"); } F.FATType = 0; int cnt = 0; if ((IDE_HDD[0].status & IDE_HDD_ATA) == IDE_HDD_ATA) { term_send_str_crlf("Disk: 0"); if ((cnt = FAT_init_Part(0,NULL,NULL,0)) == FAT_ERR) { term_send_str_crlf("Chyba pri nacitani MBR"); return; } term_send_str("Pocet aktivnich partition s FAT32: "); term_send_num(cnt); term_send_crlf(); } if (cnt > 0) { if (FAT_init_Part(0,&F,name,0) == FAT_ERR) return; switch (F.FATType) { case FAT_32: term_send_str_crlf("FAT32");break; case FAT_16: term_send_str_crlf("FAT16");break; case FAT_12: term_send_str_crlf("FAT12");break; } term_send_str_crlf("Celkova velikost [kByte]: "); term_send_num(F.Clusters * F.SecPerClus / 2); term_send_crlf(); if (F.FreeClus != 0xFFFFFFFF) { term_send_str(" Volne misto (posledni udaj): "); term_send_num(F.FreeClus * F.SecPerClus / 2); term_send_crlf(); } if (name[0] != 0) { term_send_str_crlf("Jmeno oddilu: "); term_send_str_crlf(name); } return FAT_OK; } else { term_send_str_crlf("Nenalezen zadny oddil FAT32 na discich!"); return; } if (FAT_Root_Dir(&F,&ADir) != FAT_OK) return; }
Výpis obsahu adresáře:
FAT_Set_Find(&ADir,NULL); // NULL = '*' int status; tFile file; int packed=0; // =1 pro zkrácený výpis položek while ((status = FAT_Find_Next(&ADir,name,NULL,NULL,&file)) == FAT_OK) { if ((file.attr & ATTR_VOLUME_ID) == 0) { // jmeno svazku nevypisujeme term_send_str(name);term_send_char(' '); if (!packed) { int i; for (i = 12 - strlen(name);i > 0;i--) term_send_char(' '); if ((file.attr & ATTR_READ_ONLY) > 0) term_send_char('r'); else term_send_char(' '); if ((file.attr & ATTR_HIDDEN) > 0) term_send_char('h'); else term_send_char(' '); if ((file.attr & ATTR_ARCHIVE) > 0) term_send_char('a'); else term_send_char(' '); if ((file.attr & ATTR_SYSTEM) > 0) term_send_char('s'); else term_send_char(' '); if ((file.attr & ATTR_DIRECTORY) > 0) term_send_str("DIR"); else term_send_num(file.FileSize); term_send_crlf(); } } }
Změna adresáře:
if ((name[0]== '/') || (name[0] == '\\')) { // skok do kořenového asdresáře if (FAT_Root_Dir(ADir.fat,&ADir) != FAT_OK) term_send_str_crlf("Nelze inicializovat RootDir!"); } FAT_Set_Find(&ADir,name); int status; while (((status = FAT_Find_Next(&ADir,name,NULL,NULL,&file)) == FAT_OK) && (((file.attr & ATTR_DIRECTORY) == 0) || ((file.attr & ATTR_VOLUME_ID) > 0))) WDG_reset(); if (status == FAT_ERR) term_send_str_crlf("Chyba pri hledani adresare!"); if (status == FAT_EOF) { term_send_str_crlf("Adresar nenalezen!"); } else { memcpy(&ADir,&file,sizeof(tFile)); if (ADir.StartClus == 0) FAT_Root_Dir(ADir.fat,&ADir); }
Vypsání obsahu souboru:
FAT_Set_Find(&ADir,Fname); int status; char data[64]; while (((status = FAT_Find_Next(&ADir,name,NULL,NULL,&file)) == FAT_OK) && ((file.attr & (ATTR_DIRECTORY | ATTR_VOLUME_ID)) > 0)) WDG_reset(); if (status == FAT_ERR) term_send_str_crlf("Chyba pri hledani souboru!"); if (status == FAT_EOF) term_send_str_crlf("Soubor nenalezen!"); if (status == FAT_OK) { while ((status = FAT_Read(&file,63,data)) > 0) { data[status] = 0; term_send_str(data); } }