Контроллер НГМД может выполнять 15 операций. Чтение файла состоит в поиске его в каталоге, определении его положения на диске с помощью таблицы размещения файлов и затем наборе операций чтения одного сектора. Эта процедура включает 6 шагов:
1. Включение мотора и короткое ожидание, пока он наберет скорость;
2. Выполнение операции поиска и ожидание прерывания, указывающего на завершение этой операции;
3. Инициализация микросхемы DMA для пересылки данных в память;
4. Посылка команды чтения контроллеру НГМД и ожидание прерывания, указывающего, что пересылка данных завершена;
5. Получение информации о статусе контроллера НГМД;
6. Выключение мотора.
Контроллер НГМД работает через три порта ввода/вывода. На самом деле микросхема имеет больше, чем три регистра, но доступ к большинству из них осуществляется через один порт. Эти три порта такие:
3F2H - регистр цифрового вывода
3F4H - регистр статуса
3F5H - регистр данных
IBM PC XT использует 4-хканальную микросхему DMA 8237. Канал О предназначен для регенерации памяти, он постоянно восстанавливает заряд ячеек оперативной памяти. Канал 2 предназначен для дисковых операций, а два других канала, с номерами 1 и 3, доступны через разъемы расширения для дополнительного оборудования. К сожалению, обмен память-память требует двух каналов и одним из них должен быть канал 0, поэтому такой обмен недоступен на IBM PC XT. Однако, IBM PC AT имеет 7 каналов прямого доступа к памяти и DMA автоматически используется инструкциями MOVS, существенно увеличивая производительность.
Текст программы
Код на ASM .model tiny .code .386 org 100h start: ;---выполняем цикл 8 раз mainloop: ;---включение мотора sti mov dx,3f2h ;регистр цифрового вывода mov al,28 out dx,al ;в порт 3f2h <- 00011100b mov cx,50000 ;время ожидания в циклах таймера не менее 23 мкс mot_d: loop mot_d ;ждем для разогрева мотора ;---выполнение операции поиска дорожки mov ah,15 ;код команды call ou_fdc ;в порт 3f5h <- ah (Посылаем контроллеру HГМД) mov ah,0 ;код дисковода call ou_fdc mov ah,nom_dor ;номер дорожки call ou_fdc call wa_int ;ожидание прерывания от НГМД mov cx,50000 wa_set: loop wa_set ;ожидание установки головки ;---инициализации микросхемы DMA mov al,46h ;код чтения данных контроллера HГМД out 0bh,al ;заслать в регистр режима работы DMA out 0ch,al ;сброс внутреннего трифера ;Вычисляем адрес буфера lea ax,buf mov bx,ds ;Помещаем DS в BX rol bx,4 ;Готовим вращение старшего нибла mov dl,bl ;Kопируем DL в BL and dl,0fh ;Чистим старший нибл в DL and bl,0f0h ;Чистим старший нибл в BX add ax,bx ;Складываем jnc no_cry ;Если не было переноса, то # страницы в DL inc dl ;Увеличиваем DL, если был перенос no_cry: ;Посылаем младший байт адреса out 4,al ;в порт 4h заносим адрес ОЗУ для записи данных mov al,ah ;Сдвигаем старший байт out 4,al ;Посылаем младший байт адреса mov al,dl ;Засылаем номер страницы out 81h,al ;в порт 81h номер посылаем страницы ;конец инициализации mov ax,511 ;Значение счётчика out 5,al ;в порт 5h заносим количество передоваемых байт mov al,ah out 5,al mov al,2 ;Готовим размещение канала 2 out 0ah,al ;DMA ожидает данные ;---получение указателя на базу диска mov al,1eh ;Hомер вектора указывающего на таблицу mov ah,35h ;Hомер функции int 21h ;Выполнить функцию ;---посылаем параметры чтения mov ah,66h ;код чтения одного сектора call ou_fdc ;посылаем в порт 3F5h mov ah,0 ;номер головки и накопителя call ou_fdc mov ah,nom_dor ;номер дорожки call ou_fdc mov ah,0 ;номер головки call ou_fdc mov ah,nom_sec ;номер сектора call ou_fdc mov ah,es:[bx]+3 ;код размера сектора call ou_fdc mov ah,es:[bx]+4 ;номер конца дорожки call ou_fdc mov ah,es:[bx]+5 ;длина сдвига call ou_fdc mov ah,es:[bx]+6 ;длина данных call ou_fdc call wa_int ;ожидание прерывания от НГМД ;---считывание результата mov cx,7 ;Берём байт 7 статуса lea bx,sta_buf ;Помещаем в буфер статуса next: call in_fdc ;Получаем байт mov [bx],al ;Помещаем в буфер inc bx ;Указываем на следующий байт буфера loop next ;Повторяем операцию ;---выключение мотора mov dx,3f2h ;адресс регистра цифрового вывода mov al,12 out dx,al ;в порт 3f2h <- 00001100b call show_buf ;вывод содержимого буфера на экран inc nom_sec ;следующий сектор cmp nom_sec,9 jne mainloop ;считываем следующий сектор дорожки если он <= 8 ret ;возврат управления ДОС ;---ожидание прерывания от НГМД wa_int proc ;Управление статусом прерывания 6 в байте статуса BIOS mov ax,40h ;Сегмент области данных BIOS mov es,ax ;Помещаем в ES mov bx,3eh ;Смещение для байта статуса again: mov dl,es:[bx] ;Получаем байт test dl,80h ;Проверяем бит 7 jz again ;До тех пор, пока не установлен and dl,01111111b ;Сбрасываем бит 7 mov es:[bx],dl ;Заменяем байт статуса ret ;Kонец процедуры wa_int endp ;---посылаем байт из ah в порт 3f5h ou_fdc proc mov dx,3f4h ;Адрес порта регистра статуса ke_tr: in al,dx ;al <- байт состояния НГМД test al,128 ;бит 7 установлен? jz ke_tr ;Если нет, продолжать цикл inc dx ;Указываем на регистр данных mov al,ah ;Передаваемое значение в AH out dx,al ;Посылаем значение ret ;Kонец процедуры ou_fdc endp ;---получение байта из регистра данных в al in_fdc proc mov dx,3f4h ;Адрес порта регистра статуса ke_tr2: in al,dx ;Получить значение test al,128 ;Бит 7 установлен? jz ke_tr2 ;Если нет, то проверяем снова inc dx ;Указываем на регистр данных in al,dx ;Читаем байт из регистра данных ret ;Kонец процедуры in_fdc endp ;вывод буфера на экран show_buf proc pusha mov ah,02h mov dl,10 ;в dl символ, выводимый на стандартный вывод int 21h mov dl,13 int 21h mov dl,nom_sec add dl,30h int 21h mov dl,10 int 21h mov dl,13 int 21h xor si,si mov cx,256 cycle: mov dl,buf[si] call showdx mov dl,' ' int 21h inc si loop cycle popa show_buf endp ; вывод слова из dl в шестнадцатиричном виде showdx proc near push ax push cx push dx mov ah,02h mov cx,2 loo: rol dl,4 ;Вращаем младшие 4 бита push dx and dl,000fh ;Чистим старший нибл в DL call show pop dx loop loo pop dx pop cx pop ax ret show: cmp dl,9 ;если dl<9 met1 jg met1 add dl,30h int 21h ret met1: add dl,37h ;в dl текущий символ-переключатель int 21h ret showdx endp buf db 512 dup (?) sta_buf db 10 dup (?) nom_sec db 1 ; Здесь номер сектора для чтения nom_dor db 5 ; Здесь номер дорожки для чтения end start
|