Аппаратное обеспечение IBM PC

       

Порты 0D0h-0DFh


Это управляющие порты и порты состояния второй микросхемы 8237A-5. По формату и назначению они соответствуют рассмотренным ранее для контроллера DMA компьютеров IBM PC/XT:



0D0h Управляющий регистр / регистр состояния
0D2h Регистр запроса
0D4h Регистр маски
0D6h Регистр режима
0D8h Сброс триггера байтов
0DAh Сброс контроллера
0DCh Сброс регистра маски
0DEh Маскирование/размаскирование каналов

В качестве примера использования контроллера прямого доступа к памяти приведем программу чтения сектора флоппи-диска. Мы уже описывали ее в предыдущем томе. Поэтому здесь мы не будем описывать команды контроллера НГМД и другие тонкости, имеющие отношение к работе с флоппи-дисками.

Перед началом инициализации КПДП программа должна послать в порты 0Bh и 0Ch код операции, которая будет выполняться КПДП - 46h для операции чтения и 4Ah для операции записи.

В процессе инициализации программа должна сообщить КПДП адрес буфера, куда ему следует поместить данные или откуда надо взять данные, и длину передаваемых данных в байтах.

Адрес необходимо представить в виде номера страницы и смещения. Для КПДП машины AT используется восьмибитовый номер страницы и 16-битовое смещение. Например, для адреса 23456 номер страницы - 2, смещение - 3456.

Для программирования канала 2 КПДП программа должна сначала вывести младший байт смещения в порт с адресом 4, затем вывести в этот же порт старший байт смещения и, наконец, вывести байт номера страницы в порт с адресом 81h.

Длина передаваемых данных выводится аналогично в порт с адресом 5 - сначала младший байт длины, затем старший.

После определения режима работы канала, адреса буфера и длины передаваемых данных, программа должна разрешить работу КПДП, выдав в порт с адресом 0Ch байт 2. Теперь канал прямого доступа готов к работе и будет ждать данных от контроллера НГМД.

Приведенная ниже демонстрационная программа использует несколько наиболее характерных команд контроллера НГМД. Она предназначена для работы на машине AT. Для того, чтобы она правильно работала и на машинах PC/XT, ее надо немного изменить. Изменения касаются программирования контроллера ПДП и программирования скорости передачи контроллера НГМД.


Контроллер КПДП PC/XT использует 4- битовый номер страницы буфера вместо 8-битового. Скорость передачи контроллера НГМД в машинах PC/XT не программируется, вам надо убрать соответствующие строки из программы. Еще надо обратить внимание на различное быстродействие машин AT и PC/XT и скорректировать константы в строках программы, выполняющих задержку.

Программа не проверяет, установлен ли флоппи-диск в приемный карман дисковода, поэтому перед запуском не забудьте установить диск.

#include <stdio.h> #include <stdlib.h> #include <conio.h> #include <dos.h> #include "sysp.h"

#define CYL 0

void main(void); void fdc_out(unsigned char byte); int fdc_inp(void); void int_wait(void); void dma_init(char *);

void main(void) {

unsigned i; long l; char buffer[512]; char status[7], main_status; DPT _far *fdpt; FILE *sect;

printf("\n" "\nРабота с контроллером НГМД" "\n ©Фролов А., 1991" "\n");

// Эта программа предназначена только для IBM AT

if(pc_model() != 0xfc) { printf("Эта программа предназначена только для IBM AT\n"); exit(-1); }

// Открываем файл, в который будем записывать // содержимое самого первого сектора на дискете

sect = fopen("!sector.dat","wb+");

// Устанавливаем указатель на таблицу // параметров дискеты

fdpt = get_dpt();

// Включаем мотор дисковода А: // Перед этим разрешаем прерывания

_enable(); outp(0x3F2, 0x1C);

// Выполняем задержку для разгона двигателя

for(l=0;l<200000;l++);

// Показываем содержимое регистра основного // состояния контроллера

printf("Мотор включен.\t\t"); printf("Основное состояние: %02.2X\n",inp(0x3F4));

// Перед чтением сектора необходимо установить // головку на нужную дорожку, в нашем случае это // дорожка с номером CYL.

// Выдаем контроллеру команду "Поиск"

fdc_out(0xf);

// Для команды "Поиск" требуется два байта параметров: // номер головки/номер накопителя и номер дорожки. // Мы работаем с нулевой головкой накопителя А:, // поэтому первый параметр равен 0, второй - CYL



fdc_out(0); fdc_out(CYL);

// Показываем содержимое регистра основного // состояния контроллера

printf("\n<<<Поиск>>> \t\t"); printf("Основное состояние: %02.2X\n",inp(0x3F4));

// Ожидаем прерывание по завершению операции

int_wait();

// Задержка для позиционирования головки

for(l=0;l<20000;l++);

// Для проверки результата выполнения команды // "Поиск" выдаем контроллеру команду // "Чтение состояния прерывания"

// Выводим содержимое регистра состояния // ST0 и номер дорожки после выполнения команды // "Поиск" PCN

fdc_out(0x8); printf("Состояние прерывания:\t"); printf(" ST0: %02.2X, \t", fdc_inp()); printf("PCN: %02.2X\n", fdc_inp());

// Для более глубокой диагностики состояния // контроллера выдаем контроллеру команду // "Чтение состояния накопителя", выводим // содержимое регистра состояния ST3

fdc_out(4); fdc_out(0); printf("Состояние накопителя:\t ST3: %02.2X\n",fdc_inp());

// Устанавливаем скорость передачи данных 500 Кбайтов/с, // это значение может различаться для разных типов дискет

outp(0x3F7, 0);

// Инициализация канала прямого // доступа к памяти

dma_init(buffer);

// Выдаем команду "Чтение данных"

fdc_out(0x66); fdc_out(0x0); // накопитель 0, головка 0

fdc_out(CYL); // цилиндр CYL fdc_out(0); // головка 0 fdc_out(1); // номер сектора - 1

// Передаем контроллеру технические параметры // дисковода, берем их из таблицы параметров дискеты. // Это такие параметры: // - размер сектора; // - номер последнего сектора на дорожке; // - размер промежутка; // - число считываемых/записываемых байтов

fdc_out(fdpt->sec_size); fdc_out(fdpt->eot); fdc_out(fdpt->gap_rw); fdc_out(fdpt->dtl);

// Ожидаем прерывание по завершению операции

int_wait();

// Считываем и выводим на экран байты результата // операции "Чтение данных"

printf("\n<<<Чтение сектора>>> \n"); printf(" Байты состояния (ST0,ST1,ST2,C,H,R,N):\n");



for(i=0; i<7; i++) printf("%02.2X\t", (char) fdc_inp()); printf("\n");

// Выводим содержимое считанного сектора в файл

for(i=0; i<512; i++) fputc(buffer[i],sect); fclose(sect);

// Выключаем мотор

outp(0x3F2, 0xC); }

// Вывод байта в контроллер дисковода

void fdc_out(unsigned char parm) {

_asm { mov dx,3F4h // Порт основного состояния loop_fdc_out:

in al,dx test al,80h // Проверяем готовность jz loop_fdc_out // контроллера

inc dx // Выводим байт в порт данных mov al, parm // контроллера out dx, al } }

// Ввод байта из порта данных контроллера дисковода

int fdc_inp(void) {

_asm { mov dx,3F4h // Порт основного состояния loop_fdc_inp: in al,dx test al,80h // Проверяем готовность jz loop_fdc_inp // контроллера

inc dx // Введенный байт записываем in al, dx // в регистр AX } }

// Ожидание прерывания от контроллера

void int_wait(void) {

// Разрешаем прерывания

_enable(); _asm { mov ax,40h // После прихода прерывания mov es,ax // программа обработки прерывания mov bx,3Eh // устанавливает в 1 старший бит wait_loop: // байта в области данных BIOS mov dl,es:[bx] // по адресу 0040:003E. test dl,80h // Мы ждем, когда этот бит будет jz wait_loop // установлен в 1, а затем // сбрасываем его. and dl,01111111b mov es:[bx],dl } }

// Инициализация канала прямого доступа к памяти

void dma_init(char *buf) {

unsigned long f_adr; unsigned sg, of;

// Вычисляем 24-разрядный адрес буфера для данных

f_adr = ((unsigned long)_psp << 4) + (((unsigned long)buf) & 0xffff);

// Расщепляем адрес на номер страницы // и смещение

sg = (f_adr >> 16) & 0xff; of = f_adr & 0xffff;

// На время программирования контроллера прямого // доступа запрещаем прерывания

_disable();

_asm { mov al,46h // Команда чтения данных от // контроллера НГМД.

out 12,al // Сброс триггера-указателя байта // для работы с 16-разрядными портами. // Следующий байт, выводимый в 16-разрядный // порт будет интерпретироваться // как младший.

out 11,al // Установка режима контроллера ПДП



mov ax,of // Смещение буфера, младший байт out 4,al mov al,ah // Смещение буфера, старший байт out 4,al

mov ax,sg // Номер страницы out 81h,al

mov ax,511 // Длина передаваемых данных out 5,al mov al,ah out 5,al

mov al,2 // Разблокировка канала 2 контроллера ПДП out 10,al }

// Инициализация контроллера закончена, // разрешаем прерывания.

_enable(); }

Остальные команды вы можете попробовать сами. Для получения дополнительной информации по контроллеру НГМД обратитесь к техническому руководству по IBM PC. Многое можно почерпнуть из описания микросхем дискового контроллера 765 фирмы NEC и аналогов этой микросхемы - Intel 8272A и отечественной КР1810ВГ72А.

На этом мы завершим обсуждение контроллера DMA. Советуем вам еще раз посмотреть программу, читающую сектора диска с использованием канала прямого доступа в памяти, которую мы приводили в третьей книге первого тома. Вы можете самостоятельно внести в нее некоторые усовершенствования, например, проверку перехода адреса в процессе работы канала прямого доступа через границу 128 килобайтов.


Содержание раздела