Lucrarea nr. 8
Introducere
Controller-ul DMA I8237
Accesul direct la memorie la calculatoarele PC/AT
Figura 8.1
Dintre registrele interne al lui 8237, cele folosite în programare sunt următoarele:
Figura 8.2
Biții pe zero sunt nefolosiți. Fiecare canal are asociat un bit de mascare prin care dezactivează cererile DMA (DREQ). Fiecare bit de mascare este automat pus pe 1 atunci când canalul respectiv termină un transfer, dacă canalul nu este programat pentru autoinițializare. La RESET toți biții de mascare sunt puși pe 1 logic.
Registrul de mod (Controller 1 - port 00Bh; Controller 2 - port 0D6h):
Figura 8.3
Modul de transfer DMA poate fi:
În cazul transferurilor pe bloc sau la cerere, odată ce controller-ul DMA a câștigat magistrala sistem, se transferă un bloc de date de până la 64Ko. Controller-ele de hard disk mai vechi, foloseau modul de transfer la cerere, dar, crescând viteza CPU-urilor, este mai eficient a fi folosit acesta în realizarea transferurilor cu hard disk-ul.
Figura 8.4
Pentru a muta un bloc de date dintr-o zonă de memorie în alta, cu un minim efort din partea procesorului, controller-ul 8237 include posibilitatea realizării transferurilor memorie-memorie. Prin setarea bitului 0 din registrul de comandă, canalele 0 și 1 sunt folosite în transferul memorie-memorie, transfer inițiat prin activarea soft a lui DREQ (prin registrul de inițiere transfer) pentru canalul 0. Diagrama de timp pentru un transfer DMA este prezentată în figura de mai jos (figura 8.5):
Timing comprimat - pentru a obține o lățime de bandă mai mare, acolo unde caracteristicile sistemului o permit, 8237 poate comprima timpul de transfer cu două impulsuri de tact.
8237 oferă două tipuri de codificare a priorităților, selectabile prin program. Primul tip este cel cu prioritate fixă în care ordinea de tratare a cererilor DMA este în ordinea crescătoare a numărului canalului: canalul 0 are prioritatea cea mai mare, iar canalul 3 care are prioritatea cea mai mică. Un al douilea tip de codificare a priorităților este prioritatea rotativă în care ultimul canal care a fost deservit devine cel mai puțin prioritar la o următoare cerere DMA.
Generarea adreselor - pentru a reduce numărul de pini ai circuitului 8237, liniile A8-15 din magistrala de adrese sunt multiplexate cu liniile de date. Pentru a face distincția între adrese și date este folosit semnalul ADSTB generat de către controller.
Figura 8.6
Figura 8.7
Figura 8.8
În tabelul următor sunt specifică utilizarea canalelor DMA.Canalul | Folosit la AT |
Controller |
0 |
liber |
1 (8 biți) |
1 |
SDLC (Synchronous Data Link Control) |
1 (8 biți) |
2 |
diskette adapter |
1 (8 biți) |
3 |
hard disk adapter |
1 (8 biți) |
4 |
conectarea în cascadă pentru controller-ul 1 |
2 (16 biți) |
5 |
liber |
2 (16 biți) |
6 |
liber |
2 (16 biți) |
7 |
liber |
2 (16 biți) |
Transferul DMA are două restricții de care, din nou, trebuie să ținem seama:
Prima restricție este relativ ușor de depășit: se transferă primul bloc de date, după ce acesta s-a terminat se trece la următorul bloc de date.
În continuare vom explica ce reprezintă aceste pagini de memorie. Imaginea primilor 1MB de memorie din sistem (PC/AT) este împărțită în 16 pagini a câte 64K fiecare:
Pagina |
Spațiul de adrese |
0 |
0000:0000 - 0000:FFFF |
1 |
1000:0000 - 1000:FFFF |
2 |
2000:0000 - 2000:FFFF |
3 |
3000:0000 - 3000:FFFF |
4 |
4000:0000 - 4000:FFFF |
5 |
5000:0000 - 5000:FFFF |
6 |
6000:0000 - 6000:FFFF |
7 |
7000:0000 - 7000:FFFF |
8 |
8000:0000 - 8000:FFFF |
9 |
9000:0000 - 9000:FFFF |
A |
A000:0000 - A000:FFFF |
B |
B000:0000 - B000:FFFF |
C |
C000:0000 - C000:FFFF |
D |
D000:0000 - D000:FFFF |
E |
E000:0000 - E000:FFFF |
F |
F000:0000 - F000:FFFF |
Tabelul 8.2
În tabelul 8.2 au fost trecute adresele logice ale paginilor. O adresă logică este formată din un segment și un offset (deplasament). Atât segmentul cât și deplasamentul în cadrul segmentului sunt pe 16 biți. Adresa fizică la 8086 și în modul real la 80x86 este pe 20 biți și se obține din adresa logică prin următoarea formulă:adresa fizică (20 biți) = segment (16 biți)*16 + offset (16 biți)
sau
adresa fizică (20 biți) = segment (16 biți)<<4 + offset (16 biți)
Următoarea structură de date (definită în limbaj de asamblare) conține cele trei elemente care definesc un transfer DMA:
Pentru calculul paginii și a deplasamentului în cadrul paginii (primii 4 biți din adresa fizică reprezintă pagina iar următorii 16 biți reprezintă deplasamentul), avem nevoie de o rutină care primește la intrare o adresă logică și returnează adresa fizică calculată din cea logică.dma_block STRUC dma_page db ? dma_offset dw ? dma_length dw ? dma_block ENDS
calc_address PROC NEAR ; input : ax - segment ; dx - offset ; output: ax - page (first 4 bits) ; dx - offset (next 16bits) ... RET calc_address ENDP
Lungimea length a blocului de transferat prin DMA se specifică controller-ului DMA prin valoarea length - 1. Deci dacă trimitem controller-ului o lungime 0 el va face un transfer pe un octet, iar dacă-i trimitem valoarea 0FFFFH, transferul va fi de 64K.
Exisă trei porturi folosite pentru a programa un canal DMA:
Tabelul următor conține adresele acestor porturi pentru registrele fiecărui canal:
Canalul DMA |
Pagina |
Adresa |
Lungime |
0 |
087h |
000h |
001h |
1 |
083h |
002h |
003h |
2 |
081h |
004h |
005h |
3 |
082h |
006h |
007h |
4 |
08Fh |
0C0h |
0C2h |
5 |
08Bh |
0C4h |
0C6h |
6 |
089h |
0C8h |
0CAh |
7 |
08Ah |
0CCh |
0CEh |
Tabelul 8.3
Deoarece controller-ului DMA i se pot trimite doar cuvinte pe 8 biți, cuvintele pe 16 biți se trimit prin două scrieri succesive la același port, prima data se scrie octetul mai puțin semnificativ iar apoi octetul mai semnificativ.
În continuare vom prezenta pașii urmați pentru programarea unui transfer DMA.
Zona de date a programului va conține:
Pașii necesari pentru programarea unui transfer DMA memorie-port sau port-memorie.; Definirea unui tip de date structura ce contine informatiile necesare unui transfer DMA dma_block STRUC dma_page db ? dma_offset dw ? dma_length dw ? dma_block ENDS; Declararea a 8 variabile de tipul dma_block pentru cele 8 canale DMA dma_data dma_block <,,>, <,,>, <,,>, <,,>, <,,>, <,,>, <,,>, <,,>; Adresele de port ale registrelor de pagina pentru fiecare canal dma_page dw 087h, 083h, 081h, 082h, 08Fh, 08Bh, 089h, 08Ah; Adresele de port ale registrelor de adresa pentru fiecare canal dma_address dw 000h, 002h, 004h, 006h, 0C0h, 0C4h, 0C8h, 0CCh; Adresele de port ale registrelorde lungime pentru fiecare canal dma_length dw 001h, 003h, 005h, 007h, 0C2h, 0C6h, 0CAh, 0CEh; Adresele de port ale registrelor de mascare pentru fiecare controler dma_mask dw 00Ah, 0D4h; Adresele de port ale registrelor de mod pentru fiecare controler dma_mode dw 00Bh, 0D6h; Adresele de port ale registrelor de flip-flop pentru fiecare controler dma_flipflop dw 00Ch, 0D8h; Adresele de port ale registrelor de comanda pentru fiecare controler dma_command dw 008h, 0D0h; Adresele de port ale registrelor de stare pentru fiecare controler dma_status dw 008h, 0D0h; Adresele de port ale registrelor de initiere transfer pentru fiecare controler dma_request dw 009h, 0D2h
Pașii necesari pentru programarea unui transfer DMA memorie-memorie.* rezerva spatiu in memorie pentru transfer; * foloseste canalul DMA corespunzator dispozitivului extern cu care se lucreaza; * dezactiveaza intreruperile; * mascheaza canalul; * initializeaza registrul flipflop; * seteaza registrul de mod corespunzator transferului dorit - scriere in memorie: 45h - citire din memorie: 49h * calculeaza adresa fizica pentru zona de memorie implicata in transfer; * incarca registrul de pagina cu valoarea obtinuta pentru pagina; * incarca registrul de adrese cu valoarea offset-ului; * incarca registrul contor cu lungimea sirului de caractere; * demascheaza canalul; * valideaza intreruperile.
* rezerva spatiu in memorie pentru transfer; * foloseste canalele DMA 0 si 1 pentru transferul memorie-memorie, canalul 0 folosit pentru citire din memorie(din zona sursa) iar canalul 1 pentru scriere in memorie (in zona destinatie); * dezactiveaza intreruperile; * mascheaza canalele 0 si 1; * initializeaza registrul flipflop; * seteaza registrul de mod pentru canalul 0; * seteaza registrul de mod pentru canalul 1; * calculeaza adresa fizica pentru zona de memorie sursa; * incarca registrul de pagina al canalului 0 cu valoarea obtinuta pentru pagina; * incarca registrul de adrese al canalului 0 cu valoarea offset-ului; * incarca registrul contor al canalului 0 cu lungimea sirului de caractere; * calculeaza adresa fizica pentru memoria video; * incarca registrul de pagina al canalului 1 cu valoarea obtinuta pentru pagina; * incarca registrul de adrese al canalului 1 cu valoarea offset-ului; * incarca registrul contor al canalului 1 cu lungimea sirului de caractere; * seteaza registrul de comanda pentru transferul memorie-memorie; * demascheaza canalul; * valideaza intreruperil; * initiaza transferul prin setarea unui bit in registrul de initiere, corespunzator canalului 0.
SAU
2. Să se realizeze un program în limbaj de asamblare care realizează un transfer DMA între memorie și placa de sunet, realizându-se, astfel, un program care trimite în fundal un set de date plăcii de sunet.